Sliver

Stupefyee's avatar
Dec 31, 2024
Sliver

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, ), ), ], ), ); } }
notion image
notion image
notion image
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, // 배경색을 빨간색으로 설정 ), ), ], ), ); } }
notion image
notion image
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; // 항상 재구성하도록 설정 } }
notion image
notion image
notion image
Share article

stupefyee