플러터에서 쓰이는 scroll 관련 위젯 중 기본적으로 많이 쓰이는 위젯들만 정리해봤다.
( 내가 나중에 보고 쓸 목적으로다가.. )
Column내부에 ScrollView를 넣을 때는 Expanded를 사용해야 함.
개념 상 height는 무한하기 때문
SingleChildScrollView
화면에 보이지 않는 위젯도 렌더링
- 보통 사용할 때에는 SingleChildScrollView의 child에 Column을 넣어서 사용한다.
- child의 크기가 화면을 넘어가지 않으면 스크롤이 되지 않으며 화면을 넘어갔을 때만 스크롤을 할 수 있다
속성
- physics: SingleChildScrollView의 스크롤이 어떻게 작용을 하는지 정할 수 있다
- 기본값: NeverScrollableScrollPhysics
- 화면을 넘어가지 않았을 때도 스크롤: AlwaysScrollableScrollPhysics
- 화면 위로 스크롤 했을 때 튕기는: BouncingScrollPhysics
- ios의 기본 설정
- 튕기지 않음: ClampingScrollPhysics
- Android의 기본 설정
- 캐러셀 처럼 작동 : PageScrollPhysics
- clipBehavior: 스크롤이 될때 child의 크기만큼만 height를 가지고 있기 때문에 내용이 잘리게 되는데 이와 관련된 설정 가능
- Clip.antiAlias, Clip.antiAliasWithSaveLayer, Clip.hardEdge: 기본 값
- 다 잘림. 모두 퍼포먼스 차이
- Clip.none: 잘리지 않는다
ListView
위에서 아래로 위젯들을 배치!
- ListView 를 바로 사용?
- 모든 위젯 렌더링
- ListView.builder
- 보이는 화면들만 렌더링
- ListView.separated
- 보이는 화면들만 렌더링
- 위젯 사이 사이마다 위젯 render 가능
속성
- scrollDirection: 스크롤의 방향 설정 ( 말그대로 😉 )
- children: Widget[]
GridView
Grid 형식으로 리스트들을 배치!
- GridView.count
- 모든 위젯 렌더링
속성
- crossAxisCount: row 마다 위젯을 몇 개를 넣을 것이냐
- crossAxisSpacing: column gap
- mainAxisSpacing: row gap
- GridView.builder
⇒ 보이는 화면만 위젯 렌더링
속성
- gridDelegate : SliverGridDelegate
SliverGridDelegate 종류
- SliverGridDelegateWithFixedCrossAxisCount
- 개수를 정할 수 있음
- SliverGridDelegateWithMaxCrossAxisExtent
- 위젯의 최대 크기에 따라서 자동으로 개수 조정
ReorderableListView
oldIndex와 newIndex 모두 이동하기 전 기준으로 산정한다.
⇒ dnd 가능한 위젯들을 나열하기 때문에 dnd가 끝난 이후 oldIndex, newIndex를 받아서 order를 만들기 때문
속성
- onReorder
ex) 기준 [red(0), orange(1), yellow(2)]
red를 yellow 아래로 옮기고 싶은 경우
red의 oldIndex
0
⇒ newIndex 3
yellow를 맨 위으로 옮기고 싶은 경우
yellow의 oldIndex
2
⇒ newIndex 0
// List<int> numbers = List.generate(100, (index) => index); // const RAINBOW_COLORS = [ // Colors.red, // Colors.orange, // Colors.yellow, // Colors.green, // Colors.blue, // Colors.indigo, // Colors.purple // ]; body: ReorderableListView.builder( itemCount: numbers.length, itemBuilder: (context, index) { return renderContainer( color: RAINBOW_COLORS[numbers[index] % RAINBOW_COLORS.length], index: numbers[index]); }, onReorder: ((oldIndex, newIndex) { setState(() { // 위에서 아래로 옮겼을 때 if (oldIndex < newIndex) { newIndex -= 1; } final item = numbers.removeAt(oldIndex); numbers.insert(newIndex, item); }); }), ),
CustomScrollView
예를 들어 한 Column 내부에 Expanded로 감싼 ListView, Expanded로 감싼 GridView가 있을 경우, ListView를 다 스크롤하고 나서 GridView가 뜨는 것을 기대했다면, 전혀 그렇게 작동되지 않는다.
화면의 반을 ListView가, 나머지 반을 GridView가 먹게 된다.
이것이 아닌, ListView를 다 스크롤하고 나서 GridView가 뜨는 것을 구현하고 싶다면 바로 그때
CustomScrollView
위젯을 사용하면 된다. 속성
- slivers: 가능한 scroll 위젯들을 넣을 수 있음 ( children 이라고 생각하면 편하다 )
- Sliver이 붙은 위젯들만 써라.. 아니면 오류 뿜뿜
그렇다면 slivers에 어떤 sliver 위젯들을 쓸 수 있는지 정리해보자.
SliverAppBar
보면 알겠지만 걍 AppBar다.
속성
- floating: true
⇒ 스크롤 올릴 때 헤더 나오는 형식
- pinned: true
=> 웹에서 position: fixed 와 같은 기능이라고 생각하면 편함
- snap: true
- floating의 중간이 없도록 함
floating: true와 써야한다. 생각해보면 당연하다.
- stretch: true
- 한계 이상까지 상단으로 스크롤 했을 경우 scaffold의 배경색이 보이는게 아닌, appbar가 보임
- expandedHeight: double
- 앱바의 최대 크기 ( 아래로 뚱뚱해진다 )
- collapsedHeight: double
- expandedHeight에서 상단 스크롤시 최소의 앱바 height ( 평소보다 크겠지? )
- flexibleSpace: FlexibleSpaceBar
- appbar 아래에 위젯들을 넣을 수 있음
SliverList
ListView의 Sliver 위젯 버젼이다.
속성
- delegate
- SliverChildListDelegate ⇒ 모든 위젯 렌더링
- SliverChildBuilderDelegate ⇒ 보이는 위젯만 렌더링
SliverGrid
말안해도 알겠지만 GridView의 Sliver위젯 버젼이다.
- delegate
- SliverChildListDelegate
- 모든 위젯 렌더링
- SliverChildBuilderDelegate
- 보이는 위젯만 렌더링
- SliverToBoxAdapter
SliverPersistentHeader
CustomScrollView에 꼭 위젯들을 나열하는게 아닌 각 섹션의 헤더 역할을 하는 위젯을 만들고 싶은 경우가 생길 것이다. 그때 사용하면 되는 위젯.
속성
- pinned: sticky 개념
- delegate: SliverPersistentHeaderDelegate
- 다른 delegate 속성들처럼 바로 넣는 것이 아닌 class를 만들어서 넣어야한다.
class _SliverFixedHeaderDelegate extends SliverPersistentHeaderDelegate { final Widget child; final double maxHeight; final double minHeight; _SliverFixedHeaderDelegate({ required this.child, required this.maxHeight, required this.minHeight, }); @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return SizedBox.expand(child: child); } @override // MEMO: 최대 높이 double get maxExtent => maxHeight; @override // MEMO: 최소 높이 double get minExtent => minHeight; @override // MEMO: covariant => 상속된 클래스도 사용 가능 ( SliverPersistentHeaderDelegate를 상속한 클래스도 될 수 있다 ) // MEMO: oldDelegate => build가 실행이 됐을 때 이전 Delegate // MEMO: this => 새로운 delegate // MEMO: shouldRebuild => 새로 build를 해야 할지 말지 결정 ( true일 경우 빌드 다시 한다 ) bool shouldRebuild(_SliverFixedHeaderDelegate oldDelegate) { return oldDelegate.minHeight != minHeight || oldDelegate.maxHeight != maxHeight || oldDelegate.child != child; } }
Scrollbar
위에서 적은 모든 scroll 관련 위젯들은 모두 스크롤바가 뜨지 않는다.
그래서 스크롤바를 띄우고 싶다면 scroll 관련 위젯을 Scrollbar 위젯으로 감싸면 된다.
RefreshIndicator
당신이 앱을 사용했다면 겪었을 상황이겠지만, 보통 스크롤이 가능한 스크린에서 맨 위로 화면을 땡기게 되면 refresh 할 수 있게 되었을 것이다.
Scrollbar 위젯과 같이 scroll 관련 위젯을 RefreshIndicator 위젯으로 감싸면 된다.
속성
- onRefresh
- typedef RefreshCallback = Future<void> Function();
SliverToBoxAdapter
예를 들어 Sliver 위젯이 아닌 Text 위젯을 꼭 CustomScrollView 위젯 내부에 넣어야겠다! 싶을 때 쓰면 된다. 단일 위젯을 표현할 때 쓴다고 생각하자.
SliverToBoxAdapter( child: Text('Text'), )
SliverPadding
딱 봐도 Padding 위젯의 Sliver 버젼이다.
SliverPadding( padding: const EdgeInsets.all(12.0), sliver: SliverToBoxAdapter( child: Text('Text'), ), )