1. 개념
- Flutter에서 **"스크롤 가능한 화면 조각"**을 의미.
- 스크롤 뷰(CustomScrollView) 안에서만 사용 가능.
- 다양한 스크롤 동작과 레이아웃을 지원.
2. 활용 예시
- 동적 화면 구현:
- 상단은 SliverAppBar로 헤더 구성.
- 중단은 SliverList로 아이템 배치.
- 하단은 SliverToBoxAdapter로 일반 위젯 추가.
3. 코드
v1
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// CustomScrollView 위젯을 사용하여 화면에 슬리버(Sliver) 구조를 추가
body: CustomScrollView(
slivers: [
// SliverAppBar: 스크롤 가능한 앱바
SliverAppBar(
title: Text("AppBar1"), // 앱바의 제목
pinned: false, // 앱바를 고정하지 않음
floating: true, // 스크롤을 살짝 올리면 앱바가 나타나도록 설정
snap: true, // 앱바가 스크롤 동작에 따라 완전히 나타나거나 사라지도록 설정
expandedHeight: 250, // 앱바가 확장될 때의 높이
flexibleSpace: FlexibleSpaceBar(
title: Text("플랙시블 스페이스"),
centerTitle: true, // 제목을 가운데로 정렬
background: Image.network(
"https://picsum.photos/200/300", // 배경 이미지 URL
fit: BoxFit.cover, // 이미지의 크기를 채우도록 설정
),
),
),
// SliverList: 리스트 아이템을 슬리버로 표시
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return ListTile(title: Text("제목 $index")); // 리스트 아이템 생성
},
childCount: 30, // 총 30개의 아이템 생성
),
),
// SliverFillViewport: 화면을 채우는 뷰포트 슬리버
SliverFillViewport(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Card(
child: Container(
color: Colors.blue[index % 9 * 100], // 배경색을 변경
child: Text("Viewport"),
),
);
},
childCount: 10, // 총 10개의 카드 생성
),
),
// SliverToBoxAdapter: 기본 위젯을 슬리버 안에 넣을 수 있도록 하는 어댑터
SliverToBoxAdapter(
child: Container(
color: Colors.red,
height: 300,
),
),
],
),
);
}
}



v2
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
title: Text("AppBar1"),
pinned: false,
floating: true,
snap: true,
expandedHeight: 250,
flexibleSpace: FlexibleSpaceBar(
title: Text("플랙시블 스페이스"),
centerTitle: true,
background: Image.network(
"https://picsum.photos/200/300",
fit: BoxFit.cover,
),
),
),
// SliverFillRemaining: 남은 공간을 채우는 슬리버
SliverFillRemaining(
child: Container( // 컨테이너를 사용하여 배경색 설정
color: Colors.red, // 배경색을 빨간색으로 설정
),
),
],
),
);
}
}


v3
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
title: Text("AppBar1"),
pinned: false,
floating: true,
snap: true,
expandedHeight: 250,
flexibleSpace: FlexibleSpaceBar(
title: Text("플랙시블 스페이스"),
centerTitle: true,
background: Image.network(
"https://picsum.photos/1080/720",
fit: BoxFit.cover,
),
),
),
// SliverToBoxAdapter: 일반 위젯을 Sliver로 변환하여 추가
SliverToBoxAdapter(
child: Container(color: Colors.blue, height: 300), // 파란색 컨테이너
),
// SliverPersistentHeader: 스크롤 시 고정 가능한 영역을 표시
SliverPersistentHeader(
pinned: true, // 스크롤 내릴 때 최소 높이로 고정됨
delegate: MySliverPersistentHeaderDelegate(
minHeight: 50, // 최소 높이 설정
maxHeight: 120, // 최대 높이 설정
child: Container(
color: Colors.yellow, // 배경을 노란색으로 설정
),
),
),
/////////////
SliverList(
delegate: SliverChildBuilderDelegate(
childCount: 30,
(context, index) {
return ListTile(title: Text("제목 $index"));
},
),
),
],
),
);
}
}
// SliverPersistentHeaderDelegate를 커스터마이즈한 클래스
class MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
MySliverPersistentHeaderDelegate({
required this.minHeight, // 최소 높이
required this.maxHeight, // 최대 높이
required this.child, // 표시할 자식 위젯
});
final double minHeight; // 최소 높이
final double maxHeight; // 최대 높이
final Widget child; // 자식 위젯
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return child; // 자식 위젯을 반환
}
@override
double get maxExtent => maxHeight; // 최대 높이 반환
@override
double get minExtent => minHeight; // 최소 높이 반환
@override
bool shouldRebuild(covariant MySliverPersistentHeaderDelegate oldDelegate) {
return true; // 항상 재구성하도록 설정
}
}



Share article