Help us understand the problem. What is going on with this article?

ConstraintLayout入門その3 - percent

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よりも柔軟です。

layout_constraint_1
<?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入門その1ConstraintLayout入門その2と歩みの遅いシリーズですが、ConstraintLayoutの習得は遠回りのようでも少しずつ出来ることを増やしていくのが確実だと思います。

参考文献

Constraintlayout | Android デベロッパー | Android Developers
ConstraintLayout | Android Developers

余談

percentという名を使っていますが百分率ではありません (1分率) 。 'proportion' などの名前にしなくてよかったのでしょうか…?

yamadacsa
フリーランスのAndroidアプリプログラマです。
https://github.com/csayamada
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした