FlutterのColumnとRowを使ってみた
大阪オフィスの山田です。最近、プライベートでFlutterでごにょごにょするのにハマっています。今回、Column
とRow
を使って、レイアウトを作ってみました。元ネタは公式のこちら。※色々試しながら実装した部分が多いので、参照先とはソースコードが異なります。
開発環境
flutter doctor
の結果です。
Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel beta, v0.5.1, on Mac OS X 10.13.5 17F77, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK 28.0.1) [✓] iOS toolchain - develop for iOS devices (Xcode 9.3) [✓] Android Studio (version 3.1) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [!] VS Code (version 1.25.1) [✓] Connected devices (1 available)
VS CodeのWarningが消えない...(´;ω;`)うっ...
(実際にはExtensionのインストールはうまくいっている)。
作るレイアウト
それではがんばっていきます。
最初にエリア分け
全体はカードになっています。そしてカードの中は以下のようにエリア分けができます。
それぞれのAreaは一列に縦に並んでいる
と考えて、Column
を使用します。なので、Widgetのbuildを以下のように書きます。
Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Card Layout"), ), body: Card( elevation: 4.0, margin: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset('assets/neko1_600x400.jpg'), _titleArea(), _buttonArea(), _descriptionArea() ], ), ) ); }
body部分ですが、まず上下左右のマージンを16取ってCardを配置します。そのchildにColumn
を用意して、各要素を縦に並べていきます。画像は本来はAspectFitのような処理を入れるべきですが、今回はassetを表示しているだけにしています。続いて、Title Area
Button Area
Description Area
を描画する処理にうつります。
Title Area
続いてTitle Areaですが、今回自分で実装してみてこの部分が一番難しかったです。Title Areaは以下のように分割することができます。
この構造を実現するのに以下の手順を行います。
- 1行目(Row)を用意する
- 1行の中には2.1、2.2、2.3があり、順番に用意していく。
- 2.1をExpand(広げる)する
- 2.1の中には縦にTextが2つ並ぶので列(Column)を用意する。
- 3.1.1、3.1.2を用意する。
上記手順を実現したソースコードです。
Widget _titleArea() { return Container( margin: EdgeInsets.all(16.0), child: Row( // 1行目 children: <Widget>[ Expanded( // 2.1列目 child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Container( // 3.1.1行目 margin: const EdgeInsets.only(bottom: 4.0), child: Text( "Neko is So cute.", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16.0), ), ), Container( // 3.1.2行目 child: Text( "Osaka, Japan", style: TextStyle(fontSize: 12.0, color: Colors.grey), ), ), ], ), ), Icon( // 2.2列目 Icons.star, color: Colors.red, ), Text('41'), // 2.3列目 ], ) ); }
Button Area
Button部分は以下のように分解することが可能です。
Title Areaの時と同様に、手順化します。
- 1行目(Row)を用意する
- 1行の中には2.1、2.2、2.3があり、順番に用意していく。
- 2の中は2行に分かれているため、Columnを用意して3.1.1,3.1.2を縦に並べる
上記手順を実現したソースコードです。
Widget _buttonArea() { return Container( margin: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 16.0), child: Row( // 1行目 crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ _buildButtonColumn(Icons.call, "CALL"), // 2.1 _buildButtonColumn(Icons.near_me, "ROUTE"), // 2.2 _buildButtonColumn(Icons.share, "SHARE") // 2.3 ], )); } Widget _buildButtonColumn(IconData icon, String label) { final color = Theme.of(context).primaryColor; return Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Icon(icon, color: color), // 3.1.1 Container( // 3.1.2 margin: const EdgeInsets.only(top: 8.0), child: Text( label, style: TextStyle( fontSize: 12.0, fontWeight: FontWeight.w400, color: color), ), ) ], ); }
1行目をRowで用意して、各ボタンのColumnを別メソッド_buildButtonColumn
で構築する流れになります。MainAxisAlignment.spaceEvenly
で、各要素間のスペースを均等にしています。アイコンとタイトルの間は、タイトルをContainer
でラップしてマージンを取っています。
Description Area
Description AreaはExpandedで最大限領域を確保して、ContainerでラップしたTextを配置しているだけです。
Widget _descriptionArea() { return Expanded( child: Container( margin: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 16.0), child: Text(''' The Neko is very cute. The Neko is super cute. Neko has been sleeping during the day time. She gets up in the evening. she is playing around at night. She nestles up to me when I get a snack. She gets angly when I pick herup. She cries out like end of the world when I take her to the bathroom. When I am asleep she goes on. Therefore, sometimes, I can be apologized. '''), ), ); }
以上となります。
最後に
まだまだ思い通りに動かせず、サンプルや公式のマニュアルを見ながら「こーやったらどうなるんだろ?」を繰り返して試行錯誤している段階です。今後もちょっとずつ学習を進めようかと思いますのでよろしくお願いします。