Androidの新しいLayout、ConstraintLayoutことはじめ


Android Studio 2.2 previewより、ConstraintLayoutという新しいLayoutが導入されました。本稿では実際に触ってみた操作感や実装方法などについて紹介します。

![Screen Shot 2016-05-19 at 22.50.14.png](https://qiita-image-store.s3.amazonaws.com/0/39433/e82cf020-4802-a27e-0934-27c4ad275e94.png "Screen Shot 2016-05-19 at 22.50.14.png")

#ConstraintLayoutとは
ConstraintLayoutは自動的にレイアウトの位置をマテリアルデザインに沿った最適な位置に調整してくれます。iOSでいうところのStoryboardのAutoLayoutのような機能をもったレイアウトです。
具体的な特徴として

- AutoConnectという機能を使って最適なレイアウトを調整できる
- Android Studioが自動的に一番フラットなxmlを生成してくれる
- Inferenceという機能で全体の整合性も調整できる
- API 9 までのバックポート対応
- 同梱ライブラリではなく、導入してもサイズが小さい (100kb) 

ということが挙げられます。
これまでレイアウトを作る場合、開発者はほぼ間違いなくxmlを自分で書いていましたが、ConstraintLayoutを使うことでその作業から開放され、開発スピードが向上します。

#利用の前提条件
2016/5/19現在、ConstraintLayoutを使うためにはAndroid Studio 2.2 previewが必要です。またJDKも1.8を利用するようにします。
File->Other Settings->Default Project Structure->SDKsでJDK1.8を設定してあげます。


![Screen Shot 2016-05-19 at 22.06.13.png](https://qiita-image-store.s3.amazonaws.com/0/39433/a7f3b802-f688-5747-6172-66fcab6a8d98.png "Screen Shot 2016-05-19 at 22.06.13.png")

#準備
ConstraintLayoutを使うにはdependenciesの追加するだけでOKです。

```
dependencies {
  compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha1'
}
```

#レイアウトの設定
以下のようにレイアウトを設定した後、 **Designタブに切替えます。**

```
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</android.support.constraint.ConstraintLayout>
```

また、blueprintボタンを押してレイアウト構造を見やすくします。
![Screen Shot 2016-05-19 at 22.08.52.png](https://qiita-image-store.s3.amazonaws.com/0/39433/6f5d13da-cf84-b51b-8d0d-1730450d45c5.png "Screen Shot 2016-05-19 at 22.08.52.png")



# AutoConnectを利用したレイアウトの配置
AutoConnectは標準でONですが、ここのUマークをクリックすると有効になります。
![Screen Shot 2016-05-19 at 22.10.21.png](https://qiita-image-store.s3.amazonaws.com/0/39433/a9e57119-8fce-0705-d522-3aed420a461b.png "Screen Shot 2016-05-19 at 22.10.21.png")


##基本的な操作方法
Viewの枠に現れる◎をクリックすると、自動的に最寄りの端に矢印が伸びます。
![Screen Shot 2016-05-19 at 22.14.19.png](https://qiita-image-store.s3.amazonaws.com/0/39433/e05241dd-58ba-9bd0-6999-20b96e50426b.png "Screen Shot 2016-05-19 at 22.14.19.png")

最適な高さに調整してくれます。もう一度クリックすると制約が消えます。

![Screen Shot 2016-05-19 at 22.15.28.png](https://qiita-image-store.s3.amazonaws.com/0/39433/14ed1021-bd98-f37c-a33c-19dd9d6e6102.png "Screen Shot 2016-05-19 at 22.15.28.png")

動いている動画はこちら
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">こんな感じでニョロっと適切な位置に配置してくれる。 <a href="https://twitter.com/hashtag/io16jp?src=hash">#io16jp</a> <a href="https://t.co/owo1IbbrO0">pic.twitter.com/owo1IbbrO0</a></p>&mdash; Tomoaki Imai (@tomoaki_imai) <a href="https://twitter.com/tomoaki_imai/status/733436165898932224">2016年5月19日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

右に出てくるProperty viewで手動で値を入力することもできます。

![Screen Shot 2016-05-19 at 22.19.01.png](https://qiita-image-store.s3.amazonaws.com/0/39433/1acbe0d5-60cc-eab9-0100-61a40820a0a7.png "Screen Shot 2016-05-19 at 22.19.01.png")

枠の中心の横長のバーはTextViewのベースラインを調整します。
その他のViewがある場合は、やはりAutoConnect機能が有効であれば自動的に線がつながって、最適な距離と位置関係を作ります。
![Screen Shot 2016-05-19 at 22.20.01.png](https://qiita-image-store.s3.amazonaws.com/0/39433/a9dc42b1-c48d-31aa-051c-411a411f0731.png "Screen Shot 2016-05-19 at 22.20.01.png")

# Property
右端にあるPropertyはViewの細かい調整ができます。右上の矢印をクリックすると、詳細な値の設定パネルが開きます。
![Screen Shot 2016-05-19 at 22.10.49.png](https://qiita-image-store.s3.amazonaws.com/0/39433/e9c49d5d-80f2-1b6c-3c95-7c321943ade8.png "Screen Shot 2016-05-19 at 22.10.49.png")

設定パネル
![Screen Shot 2016-05-19 at 22.10.56.png](https://qiita-image-store.s3.amazonaws.com/0/39433/19be2bb4-25c3-7a26-89d7-ff452a03a883.png "Screen Shot 2016-05-19 at 22.10.56.png")


#Inference機能
Inferenceも自動制約設定の機能です。以下のボタンで設定ができます。

![Screen Shot 2016-05-19 at 22.28.15.png](https://qiita-image-store.s3.amazonaws.com/0/39433/96673f6b-7cf5-bbf1-4adf-97ec0f533ad5.png "Screen Shot 2016-05-19 at 22.28.15.png")

AutoConnectとの違いはレイアウト全体の制約を定義してくれる点です。AutoConnectは部分的な制約設定しかできないので、Inferenceがあると複数のViewがある複雑な画面に対応しやすくなります。
例えば、下のようにAutoConnectで設定したレイアウトがあるとします。

![Screen Shot 2016-05-19 at 22.29.00.png](https://qiita-image-store.s3.amazonaws.com/0/39433/1dbeb884-dbca-6d19-8c09-d77b03159157.png "Screen Shot 2016-05-19 at 22.29.00.png")


このレイアウトを横回転させると以下のようにレイアウトが崩れます。このケースでは各View間でしかレイアウトの制約が設定されていないからです。

![Screen Shot 2016-05-19 at 22.29.15.png](https://qiita-image-store.s3.amazonaws.com/0/39433/054cb4da-2d3a-00c3-fb5e-0aa01532eb45.png "Screen Shot 2016-05-19 at 22.29.15.png")


Inferenceを使うと、全体のレイアウトの制約が設定されます。Inferenceを使うと、以下のように横画面でもそのままのレイアウトで画面が作られます。

![Screen Shot 2016-05-19 at 22.31.23.png](https://qiita-image-store.s3.amazonaws.com/0/39433/f2ad4ed9-e936-0cf1-ba1f-32050a5d5fc7.png "Screen Shot 2016-05-19 at 22.31.23.png")




#自動ConstraintLayout変換機能
既存のLayoutをConstraintLayoutに変更する機能もあります。DesignタブのComponentTreeからLayoutを右クリック -> Convert XXXLayout to ConstraintLayoutを選択でできます。

![Screen Shot 2016-05-19 at 22.38.22.png](https://qiita-image-store.s3.amazonaws.com/0/39433/b218cdf1-dad2-c49f-efd5-77e19e5c2fe4.png "Screen Shot 2016-05-19 at 22.38.22.png")

実際に以下のRelativeLayoutに対して実行してみました。

実行前

```xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">
    <LinearLayout
        android:id="@+id/button_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <Button
            android:id="@+id/button_show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp"
            android:text="start"/>

        <Button
            android:id="@+id/button_search"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp"
            android:text="end"/>
    </LinearLayout>
    <ScrollView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/button_layout">
        <LinearLayout
            android:id="@+id/process_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            />
    </ScrollView>
</RelativeLayout>
```

実行後

```xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="match_parent"
    tools:context=".MainActivity"
    tools:layout_editor_absoluteX="0dp"
    tools:layout_editor_absoluteY="0dp">

    <LinearLayout
        android:id="@+id/button_layout"
        android:layout_width="176dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        tools:layout_editor_absoluteX="16dp"
        tools:layout_editor_absoluteY="16dp">

        <Button
            android:id="@+id/button_show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="start"
            tools:layout_editor_absoluteX="0dp"
            tools:layout_editor_absoluteY="93dp"/>

        <Button
            android:id="@+id/button_search"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="end"
            tools:layout_editor_absoluteX="88dp"
            tools:layout_editor_absoluteY="93dp"/>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/process_view"
        android:layout_width="7dp"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        tools:layout_editor_absoluteX="16dp"
        tools:layout_editor_absoluteY="76dp"/>

</android.support.constraint.ConstraintLayout>

```

ScrollViewが消えてしまった...。また追加でConstraintの設定が必要なWarningが出ました。ちょっと変換後の動きは怪しそうです。

#まとめ
つかいこなせるとさくさくレイアウトが作れるので、かなり便利なんじゃないかなと思います。一方でこれを使ってレイアウトを作ると、沢山設定項目が増えるので、手動で調整が難しくなりそうだと感じました。また現時点では若干レイアウトが実体よりズレたり、表示がおかしい部分もあるので、注意が必要そうです。