본문 바로가기
Flutter

[Flutter] Column안에서 바로 ListView를 쓰지 말아야 하는 이유

by 김무스비 2024. 11. 14.
728x90
반응형

Column> Expanded> Listview의 구조 혹은 SingleChildScrollView> Column> Listview 의 구조를 써야하는 이유는 크게 두 가지다.


1. 레이아웃 안정

ListView는 무한한 높이를 가지려고 하기 때문에 Column 에 바로 넣으면 레이아웃 제약 조건을 위반하게 되어 Vertical viewport was given unbounded height 혹은 Cannot hit test a render box that has never been laid out.
Another exception was thrown: Assertion failed: file 
과 같은 에러가 뜨면서 실행이 안된다. 하지만, Expanded 위젯을 써주면 ListView Column 내에서 가능한 모든 공간을 차지하도록 만들어(= ListView가 무한한 높이를 가지려고 하지 않게 만들어) 레이아웃 에러를 방지할 수 있다.

 

2. 스크롤 충돌 방지

Column 자체는 스크롤이 불가능하지만, ListView는 스크롤이 가능해서 Column 안에 직접 ListView를 넣으면 스크롤 동작이 충돌할 수 있다.(물론 1번의 이유로 실행 자체가 안되는 경우가 대부분임, 그냥 expanded나 SingleChildScrollView 쓰자)


3. 사용 예시

Expanded나 Flexible을 쓰는 방법은 그냥 Wrap 해주기만 하면 되지만, SingleChildScrollView> Column> ListView 의 구조를 쓸때는 ListView에 적용해줘야 되는 속성이 2가지 있다.(그렇지 않으면 에러 생김)

1)shrinkWrap: true →  ListView의 높이를 내용에 맞게 축소해서 ListView가 무한한 높이를 가지려고 하지 않게 되어 SingleChildScrollView와 함께 사용 가능(필수)

2)physics: NeverScrollableScrollPhysics()  ListView의 자체 스크롤을 비활성해서 ListView가 스크롤되지 않고, 대신 SingleChildScrollView가 스크롤되어서 함께 사용 가능(안전장치)

더보기

//샘플 코드//

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('SingleChildScrollView Example'),
        ),
        body: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              Text('Some text'),
              ListView(
                shrinkWrap: true,
                physics: NeverScrollableScrollPhysics(),
                children: <Widget>[
                  ListTile(title: Text('Item 1')),
                  ListTile(title: Text('Item 2')),
                  ListTile(title: Text('Item 3')),
                  ListTile(title: Text('Item 4')),
                  ListTile(title: Text('Item 5')),
                  ListTile(title: Text('Item 6')),
                  ListTile(title: Text('Item 7')),
                  ListTile(title: Text('Item 8')),
                  ListTile(title: Text('Item 9')),
                  ListTile(title: Text('Item 10')),
                ],
              ),
              Text('Some more text'),
            ],
          ),
        ),
      ),
    );
  }
}

728x90
반응형