0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SingleChildScrollViewとColumn、Flexウィジェットの初歩的なミス

Last updated at Posted at 2024-07-23

挨拶

お久しぶりです、ぺんまるです。
最近Flutterでのアプリ開発を始めました。
riverpodやらfirebaseといったIT界隈に新規で参入してきたぺんぎんにはなかなか難しいものです。
また、夏も本格的にはじまり、やる気が削がれますね…
でも、アウトプットを小さいものでも形に残していき、今後は増やしていきたいと考えています。

謎にエラー処理で時間がかかった(初級者あるある?)

今回なぜ記事を書いたのかというと、謎にエラー処理で時間がかかったものを備忘録として残したいとおもって書きました。

そのエラーというものが
RenderFlex children have non-zero flex but incoming height constraints are unbounded

になります。

このエラーはなんだ?

具体的にどのようなコードを書けば、このようなエラーがでるのかというと

エラーが出たコード
// プロパティなどは省く
return SingleChildScrollView(
      child: Column(
        children: [
          Expanded(
            child: ColoredBox(
              color: Colors.green,
            ),
          )
        ],
      ),
    );

こう書くと先ほどのエラーがでます。
ある程度というか、初心者の方でも「まぁこうなるわな」ってわかる人もいると思いますが、これはSingleChildScrollViewが高さを無限に保つため、Expandedがレンダリング範囲を決められない点にあるそうです。
初心者の方、ぼくもそうなんですけど冷静にエラーを見ればどこがダメなのかがログに出力されたりしているのでわかるんですよね。

解決方法

1つ目はSizedBoxやContainerなどでラップし、固定サイズにする
→しかしこれは、レスポンシブな対応ができないことや本来したいことを実現できない可能性があります。

2つ目はLayoutBuilderやConstrainedBoxで親widgetの高さと同一にする
→これはLayoutBuilderがウィジェット描画前に端末サイズを取得し、その端末サイズの高さをConstrainedBoxの最小値に入れて、レンダリングをするということですね

ただこれは、あくまでも端末サイズの中で行われるので、他のウィジェットが画面の割合を圧迫しているのであれば、高さが0になり表示されなくなります。
例えば、下記のコードを書くとします。

 return LayoutBuilder(
      builder: (context, constraints) {
        return SingleChildScrollView(
          child: ConstrainedBox(
            constraints: BoxConstraints(
              minHeight: constraints.maxHeight,
            ),
            child: IntrinsicHeight(
              child: Column(
                children: [
                  Expanded(
                    child: Container(
                      color: Colors.red,
                    ),
                  ),
                  Container(
                    height: 500,
                    color: Colors.blueAccent,
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );

エミュレータの端末サイズは
Size(411.4, 867.4)
です。
例えば上記コードであれば、青色のContainerのheightが500だと

のように表示され、867.4-500=367.4が割り当てられています。
しかし、青色のContainerheightが800、つまり端末サイズを超える場合は

上の画像のように青色のContainerがすべての領域を奪ってしまいます。
SingleChildScrollView+Rowウィジェットの組み合わせだとテキストのフレキシブルなレイアウトなど活用ができますが、Columnだと使うことがなさそうですね。
今回エラーがでたのもRowの中のColumnでラップされたTextウィジェットに対してExpandedを使ったためでした。
実際にはRow側にExpandedを使用することで対処できるので、記述位置に気をつけたいですね。

まとめ

SingleChildScrollView+Columnの組み合わせでフレキシブルなウィジェットを使う対処方法があるが、それはレイアウトの設計上使うことがなさそう?もし、使っていたとしたら記述ミスの可能性

  • Stack+imageでimageをExpandedをラップし、背景画像に使うとしてもContainerを使えば同じことができる
  • Rowの中で使うことはあるが、Columnだと端末サイズを超えるとExpandedが占める領域はなくなるため意味がない
    もし初めに書いたエラーが出た場合は、Expandedなどの記述位置が違う(本来はRowの中に書くべき)可能性あり。

まだ、アプリ開発をはじめてから3ヶ月なので、これからアプリの学習を頑張っていきたいと思います!!

参考にさせていただいた記事さま

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?