[Flutter / 플러터] 나는 sliver와 스크롤링을 제대로 알고 있을까?
Sliver
사전 의미 : 잘게 부수어 만든 작거나 얇은 조각
플러터 : 스크롤 가능한 영역의 일부분
코딩 셰프 : Sliver is a slice of something that scrolls.
스크롤 되는 영역을 이루는 조각 하나하나를 의미하는 것
slivers (복수) : 스크린 상에서 스크롤 되는 영역 의미
ListView vs. SliverList
GridView vs. SliverGrid
사실, ListView == SliverList / GridView == SliverGrid
ListView, GridView | SliverList, SliverGird |
sliver로 이루어짐 | |
위젯 O | 위젯 X |
SliverList를 한데 묶어 위젯으로 만든 것과 같음 왜냐하면 Colum, Row 위젯과 함께 사용할 수 있게 만들기 위해서 |
> SliverList는 ListView와 정확히 똑같은 기능을 하지만 위젯은 아니며 customScrollView 위젯 내에서 주로 사용되는 요소.
플러터가 화면을 그리는 방법
1. 코딩하면 각 tree를 생성
2. 부모위젯이 자식위젯의 크기나 위젯 지정
3. Render tree는 있는 각 Render object는 2정보에 근거해 위젯 그려줌. 이때 사용하는 render object의 sub클래스인 Render box는 box constraints를 전달해주는 box protocol를 사용
(box protocol : 컨테이너 위젯이나 sizedbox처럼 박스처럼 가로세로의 최대최소의 값이 얼마인지에 근거해서만 그려진다는 의미)
But 스크롤링할땐 상황이 달라짐
box 안에서 무한히 모든걸 보여줄 수 없으니 스크롤 영역 내에서 sliver를 얼만큼 보여 줄 것이며, 다음 sliver까지의 거리는 얼마이며, 어디까지 스크롤될 지가 중요해짐. = box protocol은 스크롤시 도움이 안됨
이때 sliver protocol 사용
4-1. 자식은 부모로부터 sliver constraints 전달받음
(sliver protocol : scroll, axis, scrollOffest, paintExtent 등 slivers를 그려주기 위한 정보 담겨있음
4-2. 이 정보를 바탕으로 최종적으로 화면에 그려주는 과정에서 render sliver가 중요한 역할 함 = Lazily load slivers 해줌
(Lazily load sliver : 스크롤 영역에서 우리가 볼 수 있는 만큼의 sliver들만 그때그때 그려줌. ListView나 GridView도 뒷단에서는 render sliver를 사용하는 것)
여러개 ListView, GridView 등을 사용하고 싶을땐? CustomScrollView 이용
CustomScrollView
: 곧바로 slivers를 전달해서 다양한 스크롤링 이펙트를 만들 수 있게 해줌
//main.dart
import 'package:flutter/material.dart';
import 'scroll_effect.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.blue
),
home: ScrollEffect(),
);
}
}
//scroll_effect.dart
import 'package:flutter/material.dart';
class ScrollEffect extends StatefulWidget {
const ScrollEffect({Key? key}) : super(key: key);
@override
State<ScrollEffect> createState() => _ScrollEffectState();
}
class _ScrollEffectState extends State<ScrollEffect> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
title: Text('Sliver appbar'),
backgroundColor: Colors.blueGrey,
expandedHeight: 200,
leading: Icon(Icons.arrow_back),
actions: [
Icon(Icons.settings),
SizedBox(
width: 12,
)
],
//flexibleSpace: 확장되엇을 경우 설정된 expandedHeight만큼 늘어났다가 줄어들었을땐 타이틀 간소화해줌
flexibleSpace: FlexibleSpaceBar(
background: Image.asset('assets/fruit.jpg',
fit: BoxFit.cover),
),
),
],
),
);
}
}
> slivers 위젯 내에선 일반 위젯은 올수 없고 sliver 관련 위젯들만 올 수 있음
> 하지만 앱을 만들다보면 일반 위젯들도 필요할 경우가 꼭 생김. 이때 필요한게 SliverToBoxAdapter 위젯
//scroll_effect.dart
SliverToBoxAdapter(
child: GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
itemCount: 20,
primary: false,
shrinkWrap: true,
itemBuilder: (context, index){
return ImageWidget(
index: index,
);
}),
)
//main.dart
import 'package:flutter/material.dart';
import 'scroll_effect.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.blue
),
home: ScrollEffect(),
);
}
}
//scroll_effect.dart
import 'package:flutter/material.dart';
import 'image_widget.dart';
class ScrollEffect extends StatefulWidget {
const ScrollEffect({Key? key}) : super(key: key);
@override
State<ScrollEffect> createState() => _ScrollEffectState();
}
class _ScrollEffectState extends State<ScrollEffect> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
title: Text('Sliver appbar'),
backgroundColor: Colors.blueGrey,
expandedHeight: 200,
leading: Icon(Icons.arrow_back),
actions: [
Icon(Icons.settings),
SizedBox(
width: 12,
)
],
//flexibleSpace: 확장되엇을 경우 설정된 expandedHeight만큼 늘어났다가 줄어들었을땐 타이틀 간소화해줌
flexibleSpace: FlexibleSpaceBar(
background: Image.asset('assets/fruit.jpg',
fit: BoxFit.cover),
),
),
SliverToBoxAdapter(
child: GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
itemCount: 20,
primary: false,
shrinkWrap: true,
itemBuilder: (context, index){
return ImageWidget(
index: index,
);
}),
)
],
),
);
}
}
//image_widget.dart
import 'package:flutter/material.dart';
class ImageWidget extends StatelessWidget {
const ImageWidget({Key? key, required this.index}) : super(key: key);
final int index;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 150,
width: double.infinity,
child: Card(
child: Image.network(
'https://source.unsplash.com/random?sig=$index', //랜덤으로 웹에서 이미지 불러오기
fit: BoxFit.cover,
),
),
);
}
}
'공부 > Flutter' 카테고리의 다른 글
Flutter 스터디 32 웹 상의 Json 데이터 파싱해서 플러터 앱에 출력하기 (0) | 2023.03.06 |
---|---|
Flutter 스터디 31 MySQL 이용해서 플러터 앱 만들기 (0) | 2023.03.06 |
Flutter 스터디 30 Cloud Firestore 기본 구조 및 기본 CRUD (0) | 2023.03.02 |
Flutter 스터디 29 Provider - ChangeNotifierProvider와 MultiProvider (0) | 2023.03.02 |
Flutter 스터디 28 채팅 기능 (0) | 2023.02.27 |