【Flutter】Columnの中でListViewを使う時にエラーが出る

# 問題
Columnの中でListViewを使う場合、そのまま使うとListViewの大きさが定まらず、下記のようなエラーが吐かれてしまう。


```dart
Column(
   mainAxisAlignment: MainAxisAlignment.center,
   children: [
       Text('top text'),
       ListView.builder(
           //shrinkWrap: true が無い
           itemCount: 20,
           itemBuilder: (BuildContext context, int index) {
              return index % 2 == 0 ? Text('item no:$index') : Divider();
           }),
       Text('end text')
       ]
)
```

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

```

この問題に対処する方法はいくつかある。

# 対処法
## 1. `shrinkWrap: true`を使う

ListViewに対して `shrinkWrap: true`を使う。しかし、このプロパティだけだとListViewの部分をスクロールした場合、下記の図のように限界であることを示すアニメーションが再生されてしまう場合がある。そのため、```physics: NeverScrollableScrollPhysics()```を付けて無効化する。

ListViewをスクロールしたい場合は、高さの制限を設ける必要があるため、`Flexible`や`LimitedBox, SizedBox`を利用した対処法2, 3を参照


![flutter_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298844/162bf58c-5c7a-1b14-abea-5c8c2fd1ab6d.png)

結果として、下記のようなコードとなる。


```dart
Column(
   mainAxisAlignment: MainAxisAlignment.center,
   children: [
       Text('top text'),
       ListView.builder(
           shrinkWrap: true,   //追加
           physics: const NeverScrollableScrollPhysics(),  //追加
           itemCount: 20,
           itemBuilder: (BuildContext context, int index) {
              return index % 2 == 0 ? Text('item no:$index') : Divider();
           }),
       Text('end text')
       ]
)
```

## 2. Flexible, Expandedを使う
Flexibleを用いると、ListViewがOverflowする限界まで広がる
同様にExpandedも使うことができる

下記はFlexibleを利用した例

```dart
Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      Text('top text'),
      Flexible(    //Flexibleでラップ
        child: ListView.builder(
              itemCount: 600,
              itemBuilder: (BuildContext context, int index) {
                return index % 2 == 0 ? Text('item no: $index') : Divider();
            }),
      ),
      Text('end text')
])

```

![flexible.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298844/e653005e-1f7c-92c3-2f18-31fe75c4a325.gif)


## 3. LimitedBox, SizedBoxを使う

予め、ListViewの最大の大きさを定められる場合は`LimitedBox`でListViewをラップする
また、高さを可変ではなく固定したい場合は、`SizedBox`でラップする

コードはLimitedBoxを利用した例

```dart
Column(
  mainAxisAlignment: MainAxisAlignment.center, 
  children: [
    Text('top text'),
    LimitedBox(
      maxHeight: 300,    //最大の高さを指定
      child: ListView.builder(
        itemCount: 600,
        itemBuilder: (BuildContext context, int index) {
          return index % 2 == 0 ? Text('item no: $index') : Divider();
      })),
    Text('end text'),
  ])
```

![limitedBox.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298844/c0dcf335-6ac4-43c6-e041-c137205bb8f5.gif)




# 最後に
誤り等ございましたら、ご指摘くださると幸いです

# 参考文献
[How to add a ListView to a Column in Flutter? - Stack Overflow](https://stackoverflow.com/questions/45669202/how-to-add-a-listview-to-a-column-in-flutter)
[Flutter: ListView disable scrolling with touchscreen - Stack Overflow](https://stackoverflow.com/questions/50477809/flutter-listview-disable-scrolling-with-touchscreen)