Open2

【Flutter】Layout失敗事例集

NoiNoi

「失敗は成功の母」

というわけで、
FlutterでLayoutを作ってるときに失敗してきた方法をここに書いていきます。

NoiNoi

ListViewをそのままColumnの中に入れる

ListViewInColumn
class ListViewInColumnView extends StatelessWidget {
  final infList = ["Your Question", "Your Diary", "People's Question"];
  
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Text('You can search : '),
        Container(height: 30),
        ListView.builder(
          itemCount: infList.length,
          itemBuilder: (context, index) {
            return Text('# ${infList[index]}');
          },
        ),
        Container(
          height: 30,
        ),
        Text('')
      ],
    );
  }
}

Rendering Libraryから長文のお叱りメッセージをいただきます。
これでもかってくらい。長いので割愛します。

flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during performResize():
flutter: Vertical viewport was given unbounded height.
flutter: Viewports expand in the scrolling direction to fill their container. In this case, a vertical
flutter: viewport was given an unlimited amount of vertical space in which to expand. This situation
flutter: typically happens when a scrollable widget is nested inside another scrollable widget.
flutter: If this widget is always nested in a scrollable widget there is no need to use a viewport because
flutter: there will always be enough vertical space for the children. In this case, consider using a Column
...

なぜだめなのか

冷静になってBoxConstraintsを考えていけば理解できます。

Columnは縦に並べていくその性質上、Heightに対する制限がありません。
つまり、maxHeight: double.infinity()なわけです。

そんな中、無限に広がってやるぜこんちくしょうなListViewColumnの中に入れると、
放任主義で自由を愛する両親の元で、やんちゃやりまくる息子状態さながら、ListViewが無限に広がろうとしてしまいます。

だからあかんと言われるわけですね。

もしどうしてもColumnの中にListViewを入れたいのであれば2つ方法があります。

  • shrinkWrap: trueListViewに指定する方法。
  • ConstraintBoxWidgetでListViewを囲む方法。

shrinkWrap: trueListViewに指定する方法。

これはやんちゃやりまくりな息子が自分で自制心働かせて周りに合わせる感じで
勝手にサイズ調整してくれます。

こっちの方がスマートに書けるので好きだったりします。

ShrinkWrapped
class RecommendView extends StatelessWidget {
  final infList = ["Your Question", "Your Diary", "People's Question"];
  
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Text('You can search : '),
        Container(height: 30),
        ListView.builder(
          shrinkWrap: true,
          itemCount: infList.length,
          itemBuilder: (context, index) {
            return Text('# ${infList[index]}');
          },
        ),
        Container(
          height: 30,
        ),
        Text('')
      ],
    );
  }
}

ConstraintBoxWidgetでListViewを囲む方法。

両親が放任主義な分、しっかりものな家庭教師が息子の面倒を見てくれる感じですね。
確実にこのサイズで調整したい!って思うときは重宝するでしょう。

BoxConstrained以外にもFlexibleExpanded, SizedBox, LimitedBoxでConstraintsを指定しても行けたりします。

BoxConstrained
class RecommendView extends StatelessWidget {
  final infList = ["Your Question", "Your Diary", "People's Question"];
  
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Text('You can search : '),
        Container(height: 30),
        ConstrainedBox(
          constraints: BoxConstraints(
            maxHeight: 60,
          ),
          child: ListView.builder(
            itemCount: infList.length,
            itemBuilder: (context, index) {
              return Text('# ${infList[index]}');
            },
          ),
        ),
        Container(
          height: 30,
        ),
        Text('')
      ],
    );
  }
}