techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

AndroidでFlexboxLayoutを使ってViewを並べる

FlexboxLayoutなるものが出たというのをチラッと見たので、どんなものなのか試してみました。

github.com

FlexboxLayoutは、CSS Flexible Box Layout Module をAndroidに持ち込んだものらしい。
しかしまだバージョンが0.1.2(昨日は0.1.1だった)ということで、まだまだこれからいろいろ変わっていきそうです。が、とりあえず試してみます。

f:id:uentseit:20160512235121p:plain:w200

FlexboxLayoutとはなんぞやということについては、W3Cの方を読んだ方がいいかもしれません。
簡単にいうと、Viewを縦方向あるいは横方向に並べつつ、View同士の間隔や高さ、幅を柔軟に伸縮させることができるレイアウトという感じです。
まぁ、実際に動きを見てみましょう。

準備

まずは使うための準備。このあたりはGithubのREADMEの通りにやれば問題ないです。
例によってbuild.gradle(app)を以下のように編集します。

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "techium.com.webviewsample"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.google.android:flexbox:0.2.1'   // 追加
}

レイアウトファイルを作成

FlexboxLayoutを使ってレイアウトファイルを作成します。
以下のようなレイアウトを作成してみました。

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.flexbox.FlexboxLayout
    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:id="@+id/flexbox_layout"
    app:flexDirection="row"    // 8行目
    app:flexWrap="nowrap"    // 9行目
    app:alignItems="flex_start"    // 10行目
    app:justifyContent="center">    // 11行目

    <TextView
        android:text="Hello World!1"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#0000FF"/>

    <TextView
        android:text="Hello World!2"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#FFFF00"/>

    <TextView
        android:text="Hello World!3"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#FF0000"/>

    <TextView
        android:text="Hello World!4"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#FF9900"/>

    <TextView
        android:text="Hello World!5"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#FF0099"/>
</com.google.android.flexbox.FlexboxLayout>

これを実行すると以下のようになります。

f:id:uentseit:20160512235509p:plain:w200

各種属性については後でまとめるが、ここで使用しているものについてまずは説明します。

8行目、flexDirectionがまず重要で、子Viewの並び方向を指定します。ここではrow(行)を指定しているので、子Viewが横方向に並びます。
逆に、columnを指定すると縦方向に並びます。

f:id:uentseit:20160513000037p:plain:w200

9行目、flexWrapは、子Viewの並びの自動折り返し有無を指定します。 ここではnowrapを指定しているので自動折り返しは行わず、子Viewが一行に入りきらない場合でも無理やり幅を調整して詰め込んでいます。
ちなみにwrapを指定すると、以下のように子Viewのサイズを変更せず自動で折り返します。

f:id:uentseit:20160513000648p:plain:w200
最後のViewが折り返している。中央に来ているのは次のjustifyContentがcenterのため。

11行目、justifyContentは子Viewの並び方向への子Viewの張り付き位置を指定します。ここではcenterを指定してるので、真ん中に張り付きます(便宜上TextViewを減らしてます)。flex_startだと並び方向の先頭位置に張り付きます。
space_betweenはViewの間にスペースを入れてViewの並び方向いっぱいに広がります。
space_aroundはViewの前後(columnだと上下)にそれぞれスペースを入れ、Viewの並び方向に広がります。

f:id:uentseit:20160513002057p:plain:w200
flex_startを指定した場合

9行目、flexWrapは、子Viewの並びの自動折り返し有無を指定します。 ここではnowrapを指定しているので自動折り返しは行わず、子Viewが一行に入りきらない場合でも無理やり幅を調整して詰め込んでいます。
ちなみにwrapを指定すると、以下のように子Viewのサイズを変更せず自動で折り返します。

f:id:uentseit:20160513000648p:plain:w200

10行目、alignItemsは、子Viewを並べる方向(ここでは横)と交差する方向(ここでは縦)に対する、Viewの張り付き位置を指定します。flex_startは開始位置(ここでは一番上部)に張り付きます。
flex_endは逆に一番下に張り付きます(下図)。Centerだと中央に張り付きます。

f:id:uentseit:20160513002803p:plain:w200

ここまではFlexboxLayoutの属性について説明しましたが、各子Viewにも個別に指定できる属性があります。

    (・・・・略・・・)
    <TextView
        android:text="Hello World!1"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#0000FF"
        app:layout_alignSelf="flex_end"/>
(・・・・略・・・)

layout_alignSelfはalignItemsの個別版のような感じです。実行すると以下のように、"Hello World!1"だけが一番下に張り付きます。

f:id:uentseit:20160513003825p:plain:w200

各属性について

他の属性も合わせて簡単に概要をまとめました。

属性 概要
flexDirection 子Viewの並び方向
flexWrap 子Viewの並び方向への折り返し有無
justifyContent 子Viewの並び方向へのViewの張り付き位置
alignItems 子Viewの並び方向に対して交差する方向に子Viewを貼り付ける。
layout_order 子Viewの並び順を指定。数値の小さい順に並ぶ。デフォルトは1。
layout_flexGrow 子Viewを配置した結果の残りの空間に対して、子Viewが伸長する割合。伸長方向は子Viewの並び方向。デフォルトは0。
layout_flexShrink layout_flexGrowとは逆に、収縮具合を指定。デフォルトは1。
layout_alignSelf 子Viewの並び方向に対して交差する方向にViewの貼り付け位置を指定。
layout_flexBasisPercent 子Viewの並び方向に対して、layout_flexBasisPercentを指定された子Viewが親Viewに対して占める割合。
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.flexbox.FlexboxLayout
    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:id="@+id/flexbox_layout"
    app:flexDirection="row"
    app:flexWrap="nowrap"
    app:alignItems="flex_start"
    app:justifyContent="space_around">

    <TextView
        android:text="Hello World!1"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#0000FF"
        app:layout_flexGrow="0.1"/>

    <TextView
        android:text="Hello World!2"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#FFFF00"
        app:layout_order="0"
        app:layout_flexGrow="0.2"
        />
</com.google.android.flexbox.FlexboxLayout>

f:id:uentseit:20160513003900p:plain:w200

言葉では少し伝わりにくいと思いますが、実はこのあたりもW3Cのドキュメントを見ると下図のように図でわかりやすく解説されています。属性の名称も似ているので、非常に参考になります。

f:id:uentseit:20160512002156p:plain

今日のところは以上です。