ConstraintLayout入門その4 - weight

ConstraintLayoutを使用するための設定については、[ConstraintLayout入門その1](https://qiita.com/yamadacsa/items/a4fcf4de9982111cdb7c)をご覧ください。

## ConstraintLayoutの一部に対して比率割り当てする

[ConstraintLayout入門その3](https://qiita.com/yamadacsa/items/2404656951b4eeac5d80)で紹介した ```app:layout_constraintWidth_percent, app:layout_constraintHeight_percent``` は、親View（すなわちConstraintLayout）の水平方向もしくは垂直方向の長さに対する比率を設定するためのものです。ConstraintLayoutの全長よりも短い部分に対して子Viewへの比率割り当てを行いたいときは、percentでなく ```app:layout_constraintHorizontal_weight```, ```layout_constraintVertical_weight``` を使う必要があります。そして、weightを有効にするためには、ConstraintLayoutの中で子Viewの一団で[チェーン](https://developer.android.com/training/constraint-layout?hl=ja#constrain-chain)を作る必要があります。

```xml:layout_constraint_2.xml
<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との比較

<img width="360" alt="表示結果" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221967/eed4a345-ddc6-5535-b97a-6481c259f1b9.png">

[ConstraintLayout入門その3](https://qiita.com/yamadacsa/items/2404656951b4eeac5d80)と同じように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 デベロッパー](https://developer.android.com/training/constraint-layout?hl=ja)
[ConstraintLayout | Android Developers](https://developer.android.com/reference/androidx/constraintlayout/widget/ConstraintLayout)

## やっぱりLinearLayoutの上位互換じゃない？

[ConstraintLayout入門その3](https://qiita.com/yamadacsa/items/2404656951b4eeac5d80)で述べた、 ```android:layout_width``` （```android:layout_height```）にゼロより長い値を与えた上でweightを設定する、という使い方をConstraintLayoutで実現することは、チェーンとweightを使ってもできないようです。ConstraintLayoutでは長さゼロを指定しないと比率が使えない、という点はweightもpercentと変わりませんし、他の手段もなさそうです。できない、と断言する自信は筆者にはありませんので、何か秘策をご存じの方はご指摘いただけると幸いです。

そもそも長さゼロ、**MATCH_CONSTRAINT**とは何か、という話題は、次回以降に譲りたいと思います。