この記事は Takeshi Hagikura, Developer Programs Engineer による Android Developers Blog の記事 "Build flexible layouts with FlexboxLayout" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。
Posted by Takeshi Hagikura - Developer Relations Team
昨年の Google I/O では、フラットなビュー階層を維持しつつ複雑なレイアウトを構築でき、Android Studio の Visual Layout Editorでも完全にサポートされている ConstraintLayout を発表しました。
同じタイミングで FlexboxLayout をオープンソース化し、Android で CSS Flexible Layout モジュールと同じ機能が使えるようになりました。この記事では、
この例では、先ほど説明した
もう 1 つ紹介しておきたいのは、個々の子ビューに
下に示すのは、各子ビューの
このケースで使われている layout xmlファイルは、GitHub レポジトリで確認できます。
なお、スクロール可能な Flexbox コンテナは、
(RecyclerView の詳細を知りたい方は、1、2などの Android UI ツールキット チームの動画をご覧ください)
さらに複雑な FlexboxLayout の例を確認したい方は、以下をご覧ください。
同じタイミングで FlexboxLayout をオープンソース化し、Android で CSS Flexible Layout モジュールと同じ機能が使えるようになりました。この記事では、
FlexboxLayout
が特に有用ないくつかのケースを紹介します。FlexboxLayout
は、高度な LinearLayout と考えることができます。どちらのレイアウトも、子ビューを順番に配置する機能を持っているためです。LinearLayout と FlexboxLayout
のもっとも顕著な違いは、FlexboxLayout
には折り返し機能があることです。 FlexboxLayout
に flexWrap="wrap"属性を追加すると、次の図のように現在の行に十分なスペースがない場合に、ビューが新しい行に配置されるようになります。1 つのレイアウトでさまざまな画面サイズに対応
この特徴を考慮して、ビューを順番に配置しつつ、(端末のファクターの違い、画面の向きの変更、マルチウィンドウ モードでのウィンドウのサイズ変更などにより)利用できるスペースが変化した場合に次の行にビューを移動させるケースについて考えてみましょう。LinearLayout
や RelativeLayout
などの従来のレイアウトでさまざまな画面サイズに対応するには、DP を指定した複数のレイアウト(layout-600dp、layout-720dp、layout-1020dp など)を定義する必要がありました。一方、上のダイアログは FlexboxLayout
を使用した一つのレイアウトだけでできています。 この例では、先ほど説明した
flexWrap="wrap"
を設定するというテクニックを利用しています。 <com .google.android.flexbox.flexboxlayoutこれによって、子ビューが親からはみ出るのではなく、新しい行に配置されるようになり、次のようなレイアウトが得られます。
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flexwrap="wrap">
もう 1 つ紹介しておきたいのは、個々の子ビューに
layout_flexGrow
属性を設定するテクニックです。これによって、スペースが余った場合の最終的なレイアウトの見栄えを改善できます。layout_flexGrow
属性は LinearLayout
の layout_weight
属性に相当します。つまり、FlexboxLayout
は、設定された layout_flexGrow
の値に応じて、余ったスペースを同じ行に配置された子ビューに割り当てます。 下に示すのは、各子ビューの
layout_flexGrow
属性を 1
に設定している例です。そのため、余ったスペースがそれぞれの子ビューに均等に割り当てられています。 <android .support.design.widget.TextInputLayout
android:layout_width="100dp"
android:layout_height="wrap_content"
app:layout_flexgrow="1">
このケースで使われている layout xmlファイルは、GitHub レポジトリで確認できます。
RecyclerView との統合
FlexboxLayout
が提供するもう 1 つのメリットは、RecyclerViewと統合できるという点です。最新リリースであるアルファ版の新しい FlexboxLayoutManager
は、RecyclerView.LayoutManager
を拡張しています。そのため、スクロール可能な Flexbox コンテナではるかにメモリ効率がよい Flexbox の機能を使うことができます。 なお、スクロール可能な Flexbox コンテナは、
ScrollView
の中に FlexboxLayout
を配置することでも実現できますが、レイアウトに含めるアイテムの数が増えると、スムーズに動かなくなったり OutOfMemoryError が発生する可能性が高くなります。これは、FlexboxLayout
ではユーザーがスクロールして画面外に移動したビューの再利用が考慮されていないためです。 (RecyclerView の詳細を知りたい方は、1、2などの Android UI ツールキット チームの動画をご覧ください)
RecyclerView
の統合が役に立つ実例としてあげられるのは、Google Photos やニュースアプリのようなアプリです。これらはどちらも、さまざまな幅のアイテムを大量に処理する必要があります。 FlexboxLayout
のレポジトリには、例としてデモアプリが公開されています。レポジトリを見ればわかるように、RecyclerView
内のイメージの幅はまちまちです。しかし、flexWrap で折り返すように設定してあり、 FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();さらに各子ビューの
layoutManager.setFlexWrap(FlexWrap.WRAP);
flexGrow
属性(下記のコード例のように、FlexboxLayoutManager
では xml ではなく、 FlexboxLayoutManager.LayoutParams
を使用して RecyclerView の各要素の属性を設定できます)も正の値に設定してあるため、 void bindTo(Drawable drawable) {画面の向きによらず、すべてのイメージをきれいにレイアウト内に収めることができます。
mImageView.setImageDrawable(drawable);
ViewGroup.LayoutParams lp = mImageView.getLayoutParams();
if (lp instanceof FlexboxLayoutManager.LayoutParams) {
FlexboxLayoutManager.LayoutParams flexboxLp =
(FlexboxLayoutManager.LayoutParams) mImageView.getLayoutParams();
flexboxLp.setFlexGrow(1.0f);
}
}
- Playground デモアプリ -
FlexboxLayout
とFlexboxLayoutManager
を使用 - キャット ギャラリー デモアプリ -
FlexboxLayoutManager
を使用
次のステップ
ニーズに合った柔軟なレイアウトの構築に役立つその他の属性については、完全版のドキュメントをご覧ください。皆さんのフィードバックをお待ちしています。問題や機能リクエストがある場合は、GitHub レポジトリの問題にご報告ください。Posted by Takeshi Hagikura - Developer Relations Team