1
3

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入門その3 - percent

Posted at

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' などの名前にしなくてよかったのでしょうか…?

1
3
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
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?