ConstraintLayout下でlayout_widthにwrap_contentを指定したTextViewが制約を無視してはみ出すときの対処法

(タイトルが長い…笑)

以下のようなレイアウトを作成するときにハマった話です。
左右に可変テキストがあり、テキストが長くなって画面に収まらなくなるときに左側の可変テキストの末尾が省略される仕様を想定しています。
(余談ですが、Layout Editorではandroid:ellipsize="end"の指定は見た目に反映されないのですね…)

f:id:tkhs0604:20200516093441p:plain:w400
デフォルトのレイアウト
f:id:tkhs0604:20200516093444p:plain:w400
左側の可変テキストが長くなったとき
f:id:tkhs0604:20200516093449p:plain:w400
右側の可変テキストが長くなったとき


layout_constrainedWidthを指定する

結論から言うと、layout_widthにwrap_contentを指定した上で、以下のattributeを省略したいテキスト側のTextViewに指定すればOKです。

  • app:layout_constrainedWidth="true"


レイアウトファイルは以下のようになります。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="100dp"
  android:padding="16dp">

  <TextView
    android:id="@+id/textview1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:lines="1"
    android:text="可変テキスト1"
    app:layout_constrainedWidth="true"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toStartOf="@id/logoview"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintHorizontal_chainStyle="packed"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

  <View
    android:id="@+id/logoview"
    android:layout_width="24dp"
    android:layout_height="24dp"
    android:layout_marginStart="8dp"
    android:layout_marginEnd="8dp"
    android:background="@color/colorPrimary"
    app:layout_constraintBottom_toBottomOf="@id/textview1"
    app:layout_constraintEnd_toStartOf="@+id/textview2"
    app:layout_constraintStart_toEndOf="@+id/textview1"
    app:layout_constraintTop_toTopOf="@id/textview1" />

  <TextView
    android:id="@+id/textview2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:lines="1"
    android:text="可変テキスト2"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>


上記のレイアウトからapp:layout_constrainedWidth="true"の指定を除くと、TextViewが制約を無視してはみ出してしまいます。

f:id:tkhs0604:20200516094837p:plain:w400
app:layout_constrainedWidth="true"の指定を除いたときのレイアウト


developer.android.com

f:id:tkhs0604:20200515001358p:plain


match_constraintとlayout_constraintWidth_defaultの組み合わせは非推奨

この件について調べていると、match_constraintとlayout_constraintWidth_defaultの組み合わせで解決している例もあったのですが、この組み合わせは現在は非推奨のようです。
正確には、以下の値(列挙子)が非推奨になっています。

  • android:layout_constraintWidth_default="wrap"


公式ドキュメントのConstraintLayoutの使い方を解説しているページでもこの組み合わせが未だに書いてあるので、気をつけた方がよさそうです。

developer.android.com


私が探した限りでは、match_constraintとlayout_constraintWidth_defaultの組み合わせが非推奨だという公式の記述は1.1.0-beta2のリリースノート(+ConstraintLayoutソースコード内)でしか見つけられませんでした… androidstudio.googleblog.com

f:id:tkhs0604:20200516140343p:plain


ということで、app:layout_constrainedWidthを使いましょう。