Study Record

[Flutter] CustomScrollView 본문

Flutter/widget_scrollView

[Flutter] CustomScrollView

초코초코초코 2023. 3. 8. 18:41
728x90

 

✍ CustomScrollView

여러 종류의 리스트 뷰를 한 번에 사용할 수 있는 위젯이다. 한 스크롤에 여러 가지 형태의 리스트뷰(그리드 뷰, 리스트 뷰 등)를 집어넣을 수 있다. CustomSctollView 에 slivers 인자에 넣고 싶은 리스트 뷰를 넣으면 되는데  ListView, GridView 를 사용할 수 없고 SliverList, SliverGrid 로 넣어야 한다. 단일 위젯을 넣고 싶다면 SliverToBoxAdapter 위젯을 사용한다.

CustomScrollView({   
  Key? key,   
  Axis scrollDirection = Axis.vertical, 
  bool reverse = false,  
  ScrollController? controller,
  bool? primary,  
  ScrollPhysics? physics,  
  ScrollBehavior? scrollBehavior,
  bool shrinkWrap = false,
  Key? center,   
  double anchor = 0.0, 
  double? cacheExtent,  
  List  slivers = const  [],
  int? semanticChildCount,  
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,  
  ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,   
  String? restorationId,   
  Clip clipBehavior = Clip.hardEdge, 
})

 

 

SliverList, SliverGrid 모두 delegate 인자가 필요한데  둘 모두 SliverChildBuilderDelegate() 와 SliverChildListDelegate() 둘 중 하나를 사용할 수 있다. 사용 방법은 SliverList 와 SliverGrid 모두 같아서 복사해서 사용해도 된다. 

SliverChildListDelegate() 는 리스트 항목을 한 번에 생성하기 때문에 비용이 많이 들 수 있다. 반면에 SliverChildBuilderDelegate() 는 화면에 보이는 항목을 기준으로 몇 개만 생성하기 때문에 SliverChildListDelegate() 보다 비용적인 면에서 이득일 수 있다.

SliverGrid(
  delegate: SliverChildBuilderDelegate(
    (BuildContext context, int index) {
      return Container(height: 300, child: Center(child: Text("$index")));
    },
    childCount: 100,
  ),
  gridDelegate:
      SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
);

SliverList(
  delegate: SliverChildListDelegate(
    List.generate(100, (index) => index)
        .map((e) => Container(
          height: 300, 
          child: Center(child: Text("$e"))
        ))
        .toList(),
  ),
)

 

 

😶 SliverList (ListView)

CustomScrollView 에 ListView 를 넣으려면 SliverView 로 넣어야 한다. 위에서 설명했듯 delegator 인자를 상황에 맞게 사용하면 된다.

CustomScrollView(
  slivers: [
    SliverList(
      delegate: SliverChildListDelegate(
        List.generate(100, (index) => index)
          .map((e) => Container(
            height: 300, 
            child: Center(child: Text("$e"))
          ))
          .toList(),
      ), 
    ),
  ]
);

 

 

😶 SliverGrid(GridView)

CustomScrollView() 에 GridView 를 넣으려면 SliverGrid 로 넣어야 한다. delegator 인자를 상황에 맞게 사용하면 된다.

CustomScrollView(
  slivers: [
    SliverGrid(
      delegate: SliverChildBuilderDelegate(
        (BuildContext context, int index) {
          return Container(height: 300, child: Center(child: Text("$index")));
        },
        childCount: 100,
      ),
      gridDelegate:
        SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
    ),
  ]
);

 

 

😶 SliverGrid + SliverList 

 

CustomScrollView(
  slivers: [
    SliverGrid(
      delegate: SliverChildBuilderDelegate(
        (BuildContext context, int index) {
          return Container(
            color: Colors.black, 
            child: Center(child: Text("$index")),
          );
        },
        childCount: 20,
      ),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        mainAxisSpacing: 12.0,
        crossAxisSpacing: 12.0,
      ),  
    ),
    SliverList(
      delegate: SliverChildListDelegate(
        List.generate(10, (index) => index)
          .map((e) => Container(
              height: 300,
              margin: const EdgeInsets.all(16.0),
              color: Colors.deepOrangeAccent,
              child: Center(child: Text("$e")),
            ),
          )
          .toList(),
      ), 
    ),
  ]
);

 

 

😶 SliverToBoxAdapter 

CustomScrollView 의 slivers 에 리스트 뷰의 형태로 넣는 것 말고 단일 위젯을 사용하고 싶을 때 SliverToBoxAdapter() 위젯을 사용한다.

CustomScrollView(
  slivers: [
    ...,
    SliverToBoxAdapter(
      child: Column(...),
    ),
  ],
)

 

 

CustomScrollView parameter

다른 파라미터에 대해 소개하자면 다음과 같다.

 

 

😶 가로 스크롤 vs 세로 스크롤(default)

scrollDirection 인자로 세로 스크롤(Axis.vertical), 가로 스크롤(Axis.horizontal)을 정할 수 있다. 세로 스크롤일 때는 세로와 관련된 위젯(ex. Column) 가로 스크롤일때는 가로와 관련된 위젯(ex. Row)을 사용해야 한다. 기본 값은 Axis.vertical 이다.

CustomScrollView(
  scrollDirection: Axis.horizontal,
  scrollDirection: Axis.vertical,
);

 

 

😶 키보드 컨트롤

keyboardDismissBehavior 인자를 사용하면 SingleChildScrollView 에 TextField 와 같이 입력 폼이 포함될 때, 사용자가 TextField 를 클릭 시 키보드가 올라왔을 때 스크롤 시 키보드가 자동으로 내려갈지(manual) 아니면 온전히 사용자에 맡길지(스크롤 시 자동으로 키보드가 내려가지 않음, onDrag) 정할 수 있다.

CustomScrollView(
  keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.manual  
  keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag
);

 

 

😶 스크롤 모양

physics 인자를 사용하면 스크롤 모양을 설정할 수 있다.

 
인자(physics) 설명
NeverScrollableScrollPhysics 사용자가 스크롤 불가능하다.
AlwaysScrollableScrollPhysics 항상 사용자가 스크롤을 가능하게 하고 스크롤 모양은 기종 기본값을 따른다.
BouncingScrollPhysics IOS 기본 스크롤 모양으로, 튕기는 모양이다.
ClampingScrollPhysics AOS 기본 스크롤 모양이다. 
PageScrollPhysics 페이지 단위로 스크롤할 수 있다.
CustomScrollView(
  physics: AlwaysScrollableScrollPhysics(),
);

 

 

+ BouncingScrollPhysics 가 적용된 상태에서 위젯이 화면 크기보다 작을 때 스크롤 시 잘려 보일 수 있다. clipBehavior 를 Clip.none 로 하면 위젯이 잘리지 않으면서 튕기는 스크롤 모양이 된다.

CustomScrollView(
  physics: AlwaysScrollableScrollPhysics(),
  clipBehavior: Clip.none,
  ...
);
728x90