ConstraintLayoutを使用するための設定については、ConstraintLayout入門その1をご覧ください。
ConstraintLayoutの一部に対して比率割り当てする
ConstraintLayout入門その3で紹介した app:layout_constraintWidth_percent, app:layout_constraintHeight_percent
は、親View(すなわちConstraintLayout)の水平方向もしくは垂直方向の長さに対する比率を設定するためのものです。ConstraintLayoutの全長よりも短い部分に対して子Viewへの比率割り当てを行いたいときは、percentでなく app:layout_constraintHorizontal_weight
, layout_constraintVertical_weight
を使う必要があります。そして、weightを有効にするためには、ConstraintLayoutの中で子Viewの一団でチェーンを作る必要があります。
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#CAEB5E"
tools:showIn="@layout/activity_main">
<TextView
android:id="@+id/txtC2Start"
android:layout_width="30dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:gravity="center_horizontal"
android:background="@drawable/rect_frame"
android:textColor="@android:color/black"
android:textSize="14sp"
android:text="30dp" />
<TextView
android:id="@+id/txtC21"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/txtC2Start"
app:layout_constraintEnd_toStartOf="@id/txtC22"
app:layout_constraintHorizontal_weight="1"
android:gravity="center_horizontal"
android:background="@drawable/rect_frame"
android:textColor="@android:color/black"
android:textSize="14sp" />
<TextView
android:id="@+id/txtC22"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/txtC21"
app:layout_constraintEnd_toStartOf="@id/txtC23"
app:layout_constraintHorizontal_weight="2"
android:gravity="center_horizontal"
android:background="@drawable/rect_frame"
android:textColor="@android:color/black"
android:textSize="14sp" />
<TextView
android:id="@+id/txtC23"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/txtC22"
app:layout_constraintEnd_toStartOf="@id/txtC2End"
app:layout_constraintHorizontal_weight="3"
android:gravity="center_horizontal"
android:background="@drawable/rect_frame"
android:textColor="@android:color/black"
android:textSize="14sp" />
<TextView
android:id="@+id/txtC2End"
android:layout_width="50dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:gravity="center_horizontal"
android:background="@drawable/rect_frame"
android:textColor="@android:color/black"
android:textSize="14sp"
android:text="50dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
上記の5つの <TextView>
のうち、2〜4番目の3つのViewで水平方向の位置参照関係を相互に持つことによって、子View3つからなるチェーンを構成しています(最初と最後の <TextView>
は、自らは参照していても他のViewから参照されていないのでチェーンに含まれません)。このチェーンの各Viewに app:layout_constraintHorizontal_weight
を設定することで、最初と最後の <TextView>
に割り当てられている部分を取り除いた(親Viewの全体でない)部分を比率配分(ここでは 1:2:3)して表示させています。
ここで、子Viewの app:layout_constraintHorizontal_weight
を有効な設定にするためには、 android:layout_width="0dp"
, すなわち、水平方向の長さにMATCH_CONSTRAINTを指定することが必須になります(同様のことを水平方向の長さで行うためには、 app: layout_constraintVertical_weight
を使い android:layout_height="0dp"
とします)。
一方、weightを指定する場合は app:layout_constraintHorizontal_chainStyle
(app:layout_constraintVertical_chainStyle
)は指定不要です(weightを指定することで、chainStyleで設定可能な[spread], [spread inside], [packed]とは別の 'Weighted' なチェーンになる、という扱いのようです)。
LinearLayoutとの比較
ConstraintLayout入門その3と同じようにLinearLayoutとConstraintLayoutの結果を並べた表示例は上のようになります。6通りの表示例いずれも左右両端の30dpと50dpの部分を除いた長さを1:2:3に分割しようとしていますが、 app:layout_constraintWidth_percent
を使った1–2では両端を取り除いた部分にpercent合計1を割り当てているため表示がはみ出し、意図通りには表示できていません。
ConstraintLayoutのweightはLinearLayoutと同じく相互の比率が表現できていればよく、percentのような0〜1の定義域に限定されません。ただし、LinearLayoutの android:weightSum
に該当するパラメータは今のところ存在しないようですので、余白部分をweightで表したいときは、2–2, 2–3のように余白用の子View(今回のサンプルでは <Space>
を使っています)をチェーンに含ませ、このViewにもweightを設定する必要がありそうです。
サンプルコード
今回のサンプルコードは以下のリポジトリにあります。
https://github.com/csayamada/ConstraintLayout4
チェーンを使ってConstraintLayout内の部分的な長さを比率分割することができましたが、2–3のようにConstraintLayoutの水平方向および垂直方向の全体の長さを分割することももちろんできます。これでpercentと同じことができますので、チェーンの概念に慣れたら比率分割には常にweightを使うようにしてpercentのことを忘れてしまっても、差し支えないでしょう。
チェーン内の子Viewにmarginを設定するなどして表示をさらに微調整できますので、さまざまな設定を実地でお試しください。
参考文献
ConstraintLayout でレスポンシブ UI を作成する | Android デベロッパー
ConstraintLayout | Android Developers
やっぱりLinearLayoutの上位互換じゃない?
ConstraintLayout入門その3で述べた、 android:layout_width
(android:layout_height
)にゼロより長い値を与えた上でweightを設定する、という使い方をConstraintLayoutで実現することは、チェーンとweightを使ってもできないようです。ConstraintLayoutでは長さゼロを指定しないと比率が使えない、という点はweightもpercentと変わりませんし、他の手段もなさそうです。できない、と断言する自信は筆者にはありませんので、何か秘策をご存じの方はご指摘いただけると幸いです。
そもそも長さゼロ、MATCH_CONSTRAINTとは何か、という話題は、次回以降に譲りたいと思います。