Sliver 개념 이해
Sliver를 이해하기 앞서 RenderBox를 먼저 알아야한다. RenderBox는 2D 데카르트 좌표계를 가진 렌더 객체로 Flutter 레이아웃 구성요소의 대부분은 RenderBox로 구현된다. Renderbox는 부모 위젯의 제약조건 내에서 구현되는 너비높이이기 때문에 동적인 상호작용이나 스크롤에 대처하기 힘들다. (이미 높이 너비가 부모 제약에 의해 정해져있음)
이러한 동적인 상호작용에 대응하기 위해 Flutter 팀은 Sliver를 만들었다. Sliver 를 통해 기존의 부모위젯 제약조건을 활용하는 대신 Sliver Protocol 에서 제공되는 다양한 제약조건을 활용했다. 특히 RenderBox에서 구현하기 어려웠던 스크롤 효과를 구현하는데 용이하다. (GridView, Inifinitie Scroll) 기본적인 Sliver 구성요소로는SliverAppBar/SliberPersistentHeader/SliverPadding/SliverToBoxAdapter 가 있다.
CustomScrollView는 다양한 Sliver를 조합해서 복잡한 스크롤 뷰를 만들 수 있는 위젯이다. Slivers 배열에는 일반적인 위젯은 못오고 sliver만 올 수 있다. 만약 Slivers 안에 위젯을 넣고 싶다면 SliverToBoxAdapter 를 통해 넣어야한다. Slivers 안에 들어가는 Sliver들을 알아보자. 먼저 SliverAppBar는 상단 앱바로 스크롤에 따라 동적으로 구현되어 최대 펼져졌을 때 200 픽셀, 플로팅, 고정 여부, 가변영역 설정등을 할 수 있다. 다음으로 SliverList는 스크롤 가능한 리스트를 생성한다. 이때 Delegate에는 동적으로 생성하는 리스트아이템을 넣을 수 있다.(iOS UIKit의 델리게이트와 유사)
💡 Slivers 안에 Sliver 위젯만 올 수 있는 이유
sliver는 동적인 뷰의 컨텍스트에서 자신의 크기와 위치를 계산한다. 일반 위젯은 이러한 동적인 뷰 안에서 자신의 크기계산을 지원하지 않기 때문에 Sliver 컨텍스트 내에 오지 못한다.
SliverChildList 델리게이트에는 두가지 종류가 있다. SliverChildListDelegate 와 BuilderDelegate 가 있는데 전자는 리스트 타이틀이 고정으로 주어지는, 후자는 리스트 타이틀이 동적으로 지정된다.
- SliverChildListDelegate:
- 고정된 자식 목록: 모든 자식 위젯을 미리 정의
- 사용 사례: 자식 위젯의 수가 적고 고정된 경우에 적합
- 메모리 사용: 모든 자식 위젯이 미리 생성되므로 메모리 사용 고정
- SliverChildBuilderDelegate:
- 동적 자식 생성: 자식 위젯을 필요할 때만 생성
- 사용 사례: 자식 위젯의 수가 많거나 동적으로 생성해야 하는 경우에 적합
- 효율성: 자식 위젯이 필요할 때만 생성되므로 메모리 사용 효율적
FlexibleSpaceBar
//https://morioh.com/a/076a8c4deb9f/flutter-sliverappbar-examples
SliverAppBar(
title: Text("SliverAppBar Title"),
expandedHeight: 220.0,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text('Title',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
)),
background: Image.network(
'https://images.pexels.com/photos/443356/pexels-photo-443356.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
fit: BoxFit.cover,
)
),
),
위와 같이 SliverAPPBar는 동적인 상호작용에 대응하여 flexibleSpace를 통해 앱바가 확장될 때 렌더링할 위젯을 전달할 수 있다.
SliverPersistentHeader
동적인 헤더를 스크롤에 따라 고정시킬때는 아래 주요 재정의를 통해 구현한다.
1. build 메서드: 헤더의 UI를 정의
2. maxExtent와 minExtent: 헤더의 최대 및 최소 높이를 정의
3. shouldRebuild: 헤더가 다시 빌드되어야 하는지 여부를 정의
둘다 동적으로 움직이는 헤더뷰이기 때문에 차이가 명확하지 않을 수 있다. 보통 FlexibleSpaceBar는 스크롤의 맨위 헤더 이미지가 동적으로 확장되었다가 줄어드는 앱바를 만들때, SliverPersistentHeaderView는 스크롤할 때 섹션별로 헤더에 고정되게 하고 싶을때 사용된다.
SliverPadding
SliverToBoxAdapter
SliverToBoxAdapter는 일반적인 위젯을 CustomScrollView의 슬리버로 변환할 때 사용할 수 있다.
SliverFixedExtentList
SliverFixedExtendList는 모든 리스트 항목이 동일한 높이를 가지게 한다. itemExtent에 원하는 높이를 작성해준다.
SliverGrid.count
SliverGrid.count는 고정된 열 수를 가지는 그리드를 생성한다. GridView와 비슷하지만, SliverGrid는 CustomScrollView 내에서 다른 Sliver 위젯과 함께 사용할 수 있다는 차이가 있다.
SliverGrid.extent
SliverGrid.extent는 그리드 항목의 최대 너비를 기준으로 항목을 배치하는 위젯이다. 따라서 기기별 너비에 대응할 수 있다.
maxCrossAxisExtent
그리드 항목의 최대 너비를 200픽셀로 설정한다. 화면 너비에 따라 한 행에 배치될 항목의 수가 결정된다.
mainAxisSpacing
항목 간의 세로 간격을 16픽셀로 설정한다.
crossAxisSpacing
항목 간의 가로 간격을 16픽셀로 설정한다.
childAspectRatio
항목의 가로 대 세로 비율을 3:2로 설정한다.
List.generate
20개의 그리드 항목을 생성한다. 각 항목은 Container 위젯으로 구성되어 있으며, 배경색과 텍스트를 포함한다.
SliverAnimatedList
전체코드: https://gist.github.com/suojae3/19b892a990fdf1a620b078cca0ab6a59
SliverAnimatedList는 항목을 삽입, 삭제 또는 변경할 때 애니메이션을 적용할 수 있는 위젯이다
GlobalKey<SliverAnimatedListState>
SliverAnimatedList
SliverChildBuilderDelegate
부가정보: 나는 Sliver와 스크롤링을 제대로 알고 있을까?
https://www.youtube.com/watch?v=YYEtWHGW894
Sliver의 어원부터 살펴보면 무언가 거대한 것을 잘게 부숴숴 만든 작거나 얇은 조각들을 의미한다. 공식문서에서는 Sliver란 스크롤 가능한 영역의 일부분이라고 나온다. 둘을 합치면 Sliver는 스크롤된 영역을 이루는 조각 하나하나를 의미한다. 따라서 Slivers는 조각조각 sliver들을 합쳐놓은 스크롤되는 영역이라고 볼 수 있다.
그렇다면 ListView/GridView 와 SliverList/SliverGrid 의 차이점은 무엇일까? 단적으로 말하면 전자는 위젯이고 후자는 위젯이 아니다. ListView/GridView는 SliverList/SliverGrid 들을 한데 묶어서 위젯으로 만들어둔 것이다. 따라서 SliverList/SliverGrid는 ListView/GridView 와 똑같은 기능을 하지만 위젯은 아니며 customScrollView에서 주로 사용되는 하나의 요소이다.
위에서 살펴보았듯이 flutter는 뷰를 렌더링할 때 widget tree, element tree, render tree 세 개의 tree를 만들어준다. 그리고 widget tree는 render tree에 직접적으로 접근하지 않고 인터페이스인 element tree를 이용하게 된다. 또한 부모위젯이 자식위젯에게 제약이나 크기를 지정해준다. Render Tree의 Render Object들은 이러한 제약/크기 정보에 근거해 위젯을 그려주는데 이때 renderobject의 하위 클리스인 render box는 box constraint를 전달해주는 box 프로토콜을 사용한다. 박스 프로토콜은 컨테이너 위젯이나 sizedBox처럼 박스 형태로 가로세로 최대최소의 값이 얼마인지에 근거해서만 그려진다.
문제는 스크롤 할 때 나타난다. 박스 프로토콜을 이용하면 부모위젯이 지정해준 고정된 크기와 위치를 그려주는데 스크롤로 인해 보여지는 영역과 전체 영역이 달라서 문제가 생긴다. 그래서 슬리버 프토토콜을 사용한다. 슬리버는 스크롤 가능한 영역 내에서 자신의 크기와 위치를 동적으로 조정한다.
슬리버 프로콜에서 자식은 sliver constraints를 받게된다. sliver constraints에는 scroll, axis, scrollOffset, paintExtent등의 정보를 알 수 있다. 그리고 최종적으로 render sliver가 화면을 그려주게 된다.
만약 ListView, GridView를 동시에 사용하고 싶거나 스크롤링 이펙트를 주고싶다면 CustomScrollView위젯을 이용한다. CustromScrollView에는 ListView 나 GridView 가 자동적으로 썻던 Sliver를 개발자가 직접 sliver에 접근해서 쓸 수 있어서 다양한 커스터마이징을 가능하게 해준다.
'Flutter' 카테고리의 다른 글
Stateless Widget 에 const를 붙여야하는 이유 (0) | 2024.05.30 |
---|---|
flutter_localization depends on flutter_localizations from sdk which depends on intl 0.18.1 에러 (2) | 2024.05.30 |
Throw 안쓰고 에러 의미있게 처리하기 (0) | 2024.05.29 |
Flutter 프로젝트 디버그용/배포용 분리하기 (0) | 2024.05.24 |
fatal error: module 'cloud firestore' not found 이슈 (0) | 2024.05.24 |