ConstraintLayoutを使用するための設定については、ConstraintLayout入門その1をご覧ください。
ConstraintLayout自動変換があればFrameLayoutやLinearLayoutを捨てられる?
Android Studioは、レイアウトXMLファイルに書かれた既存のViewを他のViewクラスに自動変換する機能を持っており、これを使ってLinearLayoutなどをConstraintLayoutに変換することができます。しかし、本稿執筆時点の最新安定版のAndroid Studio ver.4.0.1でこの機能を試してみた結果は期待はずれ、とても自動変換だけでそのままアプリに使えるConstraintLayoutになってくれません。LinearLayoutで垂直ないし水平に並んだViewの並びをConstraintLayoutの制約表現に変える機能だけならまだしも、LinearLayoutでよく使われる android:layout_weight
などの指定が入ったレイアウトをConstraintLayoutに変換するには手作業が不可欠のようです。本稿ではその辺りを突っ込んでみます。
percent
LinearLayoutは単に子Viewをまっすぐ並べるだけでなく、 android:layout_weight
という属性を子Viewに持たせることによって、その長さを柔軟に設定することができます。ConstraintLayoutでは、 app:layout_constraintWidth_percent
, app:layout_constraintHeight_percent
の2つの属性がそれに近い機能を果たします。
ConstraintLayoutの他の多くの属性と同様、1つの子Viewに水平方向と垂直方向に独立にpercentを設定できる点において、LinearLayoutよりも柔軟です。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:background="#CAEB5E"
tools:showIn="@layout/activity_main">
<TextView
android:id="@+id/txtC11"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.167"
android:gravity="center_horizontal"
android:background="@drawable/rect_frame"
android:textColor="@android:color/black"
android:textSize="14sp" />
<TextView
android:id="@+id/txtC12"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/txtC11"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.333"
android:gravity="center_horizontal"
android:background="@drawable/rect_frame"
android:textColor="@android:color/black"
android:textSize="14sp" />
<TextView
android:id="@+id/txtC13"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/txtC12"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.5"
android:gravity="center_horizontal"
android:background="@drawable/rect_frame"
android:textColor="@android:color/black"
android:textSize="14sp" />
</androidx.constraintlayout.widget.ConstraintLayout>
上の記述例のポイントは、子Viewに android:layout_width="0dp"
を設定しているところです。ConstraintLayoutは、「長さゼロ」に MATCH_CONSTRAINT, すなわち従来からの MATCH_PARENT や WRAP_CONTENT のような特別な意味を割り当てています。「長さゼロ」のときにのみ、 app:layout_constraintWidth_percent
が無視されず意味を持ちます(同様に、 app:layout_constraintHeight_percent
を有効にするには、 android:layout_height="0dp"
が必要)。
一般に app:layout_constraintWidth_percent
, app:layout_constraintHeight_percent
には0から1の間の小数を設定し、親Viewの水平ないし垂直の長さとの比率を表します。
上の表示例は、3つのTextViewを1:2:3の長さの比率で横に並べています。percentはチェーンでも使うことができ、1–3., 2–3. はチェーンを使っています。percentの合計が1に満たないようにすると、LinearLayoutで android:weightSum
を設定して余白部分を余らせるのと同様の表示ができます。2–3. はチェーンの効果で均等配列されます。
LinearLayoutの完全上位互換ではない?
今回、LinearLayoutで android:layout_weight
を使って表示できるレイアウトのすべてをConstraintLayoutで実現するつもりで記事を書いたのですが、筆者がやってみた限りでは、表示例の3. のように「子Viewにゼロを超える長さ (ここでは100dp) を与えておいてウェイト (ここでは1:2:3) を設定する」というケースをConstraintLayoutで表現できませんでした。
LinearLayoutでこのように設定すると、子Viewで幅を100dp (ここでは262.5px) ずつ確保しておいて、さらにLinearLayoutが持っている余白を1:2:3の比率で子Viewに分配する (48.5px, 97.5px, 146.5px) という2段階の長さ割り当てが行われます。
しかしConstraintLayoutのpercentではこのような割り当てができません。percentを設定する子Viewは「長さゼロ」を指定しなければならないので子View固有の長さを設定できません。 layout_constraintWidth_min
を使っても同じようにはなりませんでした。
ConstraintLayoutはFrameLayoutやLinearLayoutなど配置用のViewGroupの完全上位互換を目指しているのかと筆者は勝手に考えていたのですが、そうではないのかもしれません。本当に上位互換でないのかどうかは、筆者の当面の宿題とさせていただくことにします。
サンプルコード
今回のサンプルコードは以下のリポジトリにあります。
https://github.com/csayamada/ConstraintLayout3
ConstraintLayout入門その1、ConstraintLayout入門その2と歩みの遅いシリーズですが、ConstraintLayoutの習得は遠回りのようでも少しずつ出来ることを増やしていくのが確実だと思います。
参考文献
Constraintlayout | Android デベロッパー | Android Developers
ConstraintLayout | Android Developers
余談
percentという名を使っていますが百分率ではありません (1分率) 。 'proportion' などの名前にしなくてよかったのでしょうか…?