2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ConstraintLayout入門その4 - weight

Posted at

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の一団でチェーンを作る必要があります。

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_chainStyleapp: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_widthandroid:layout_height)にゼロより長い値を与えた上でweightを設定する、という使い方をConstraintLayoutで実現することは、チェーンとweightを使ってもできないようです。ConstraintLayoutでは長さゼロを指定しないと比率が使えない、という点はweightもpercentと変わりませんし、他の手段もなさそうです。できない、と断言する自信は筆者にはありませんので、何か秘策をご存じの方はご指摘いただけると幸いです。

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

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?