Android ConstraintLayoutの制約を図で理解する
Start_toEndOf、Top_toBottomOfなど、名前は分かるのに一瞬迷うConstraintLayoutの制約。
「自分のどの辺を、相手のどの辺につなぐか」で整理すると簡単です。
このページは、Android StudioでXMLを書いている途中にすぐ確認するための早見表です。
Start_toEndOf="@id/A"Top_toBottomOf="@id/A"width="0dp" + Start / End1. ConstraintLayoutの基本
ConstraintLayoutでは、Viewの位置を「どこにつなぐか」で決めます。 基本は、横方向に1つ以上、縦方向に1つ以上の制約を設定します。
layout_constraintStart_toEndOf="@id/viewA" は、
「自分のStartを、viewAのEndにつなぐ」とそのまま読みます。
2. Start・End・Top・Bottom
| 名前 | 意味 | 普段の感覚 |
|---|---|---|
Start | 文字の開始側 | 日本語では通常「左」 |
End | 文字の終了側 | 日本語では通常「右」 |
Top | 上端 | 上 |
Bottom | 下端 | 下 |
通常は Left / Right より Start / End を使います。
Start / Endなら、右から左へ書く言語のレイアウトにも対応しやすくなります。
3. 横方向の制約
左端をそろえる:Start_toStartOf
app:layout_constraintStart_toStartOf="@id/viewA"Aの右側に置く:Start_toEndOf
app:layout_constraintStart_toEndOf="@id/viewA"Aの左側に置く:End_toStartOf
app:layout_constraintEnd_toStartOf="@id/viewA"右端をそろえる:End_toEndOf
app:layout_constraintEnd_toEndOf="@id/viewA"4. 縦方向の制約
Aの下に置く:Top_toBottomOf
app:layout_constraintTop_toBottomOf="@id/viewA"Aの上に置く:Bottom_toTopOf
app:layout_constraintBottom_toTopOf="@id/viewA"上端をそろえる:Top_toTopOf
app:layout_constraintTop_toTopOf="@id/viewA"下端をそろえる:Bottom_toBottomOf
app:layout_constraintBottom_toBottomOf="@id/viewA"5. parentにつなぐ
parent は、そのViewを入れているConstraintLayout自身です。
左上に置く
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"右下に置く
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"6. 中央に配置する
横方向の中央
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"画面の中央
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"7. 0dpは「0」ではない
ConstraintLayoutで特に重要なのが 0dp です。
幅や高さに指定した場合、単純な0ではなく制約に合わせてサイズを決める MATCH_CONSTRAINTとして動作します。
android:layout_width="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"0dp は「幅0」ではなく、
制約に任せると考えると分かりやすい。
| 指定 | 動き |
|---|---|
wrap_content | 中身に必要なサイズ |
0dp | 制約に合わせてサイズを決定(MATCH_CONSTRAINT) |
match_parent | ConstraintLayoutでは、必要に応じて0dp+両側制約で置き換えられる |
8. marginを付ける
Aの下に16dp空けて配置する例。
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/viewA"
横方向では layout_marginStart / layout_marginEnd、
縦方向では layout_marginTop / layout_marginBottom を使います。
9. Biasで中央からずらす
両側に制約したViewは基本的に中央に配置されます。
layout_constraintHorizontal_bias を使うと、その位置を調整できます。
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.25"縦方向は layout_constraintVertical_bias を使います。
10. Guidelineを基準にする
Guidelineは画面には表示されない基準線です。 例えば、画面幅の30%を基準にViewを置きたい場合に使えます。
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.3" />View側からは普通のViewと同じようにつなぎます。
app:layout_constraintStart_toStartOf="@id/guideline"11. Barrierで「一番長いView」の先に置く
ラベル文字数がバラバラなときはBarrierが便利です。 複数Viewのうち最も外側にある位置を、自動で基準にできます。
<androidx.constraintlayout.widget.Barrier
android:id="@+id/labelBarrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="labelName,labelAddress" />入力欄などをBarrierの右側に置きます。
app:layout_constraintStart_toEndOf="@id/labelBarrier"12. Chainで複数Viewを並べる
View同士を相互に制約するとChainを作れます。 ボタンを横に均等配置したいときなどに便利です。
| Chain style | 配置 |
|---|---|
spread | 空きスペースを均等に分配 |
spread_inside | 両端を端に寄せ、内側を均等配置 |
packed | Viewをひとまとまりにして配置 |
app:layout_constraintHorizontal_chainStyle="packed"13. 縦横比を固定する
画像やプレビューの縦横比を保ちたいときは layout_constraintDimensionRatio を使います。
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="16:9"14. TextViewの文字位置をそろえる
TextView同士を横に並べたとき、Viewの上端ではなく文字のベースラインをそろえたい場合があります。
app:layout_constraintBaseline_toBaselineOf="@id/textA"15. よく使う制約 早見表
| やりたいこと | 指定 |
|---|---|
| 親の左に合わせる | Start_toStartOf="parent" |
| 親の右に合わせる | End_toEndOf="parent" |
| 親の上に合わせる | Top_toTopOf="parent" |
| 親の下に合わせる | Bottom_toBottomOf="parent" |
| Aの右側に置く | Start_toEndOf="@id/A" |
| Aの左側に置く | End_toStartOf="@id/A" |
| Aの下に置く | Top_toBottomOf="@id/A" |
| Aの上に置く | Bottom_toTopOf="@id/A" |
| 横中央 | StartとEndをparentへ |
| 縦中央 | TopとBottomをparentへ |
| 横幅を制約いっぱい | width="0dp" + Start / End |
| 縦幅を制約いっぱい | height="0dp" + Top / Bottom |
16. 実際のXML例
タイトルの下にボタンを置き、ボタンを横方向中央に配置する例です。
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="タイトル"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="決定"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" />17. 位置がおかしいときの確認順
- 横方向の制約が1つ以上あるか
- 縦方向の制約が1つ以上あるか
Start_toEndOfとEnd_toStartOfを逆にしていないかwrap_contentと0dpのどちらが適切か- marginを付ける方向が合っているか
- 両側制約がある場合、Biasが変更されていないか
18. よくある疑問
Start_toEndOfが毎回分からなくなる
「自分のStartを、相手のEndにつなぐ」と読めばOKです。 つまり、自分を相手の右側に置く指定です。
ConstraintLayoutで0dpにして大丈夫?
大丈夫です。ConstraintLayoutでは0dpがMATCH_CONSTRAINTとして使われ、 左右または上下の制約に応じてViewサイズが決まります。
Viewを中央に置くには?
横ならStartとEnd、縦ならTopとBottomを両方parentにつなぎます。 Biasを指定していなければ基本位置は中央です。
19. これだけ覚えておけば困りにくい
Top_toBottomOf="@id/title"= 自分のTopをtitleのBottomにつなぐ
= titleの下に自分を置く
ConstraintLayoutで迷ったら、まず 「左はどこにつなぐ?」「右は?」「上は?」「下は?」 と考えると、ほとんどの配置は整理できます。
※ 本ページは、自分でAndroidアプリを開発するときにすぐ確認できるよう、公式情報をもとに実用部分を整理したメモです。