일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 장자명언
- Android
- Firebase
- Freesound
- 파이썬
- androidx
- 명언모음
- bash
- 공자명언
- Coroutine
- 오픈소스
- Flutter
- Streaming
- jetpack compose
- 이모지메모
- 코틀린
- 명심보감
- FSM
- kotlin
- ASMR
- 넷플릭스
- 벤자민플랭클린
- 이모지
- 좋은글필사하기
- Linux
- 소울칼리버6
- recyclerview
- 공부집중
- DART
- 1인개발자
Archives
- Today
- Total
Vintage appMaker의 Tech Blog
[Flutter] stickyheader 구현(CustomScrollView, SliverAppBar, SliverList) 본문
Source code or Tip/Flutter & Dart
[Flutter] stickyheader 구현(CustomScrollView, SliverAppBar, SliverList)
VintageappMaker 2022. 8. 13. 16:28
아래로 스크롤 시, 특정 아이템이 상단에 픽스되기를 원한다면 Flutter에서는 CustomScrollVIew를 이용하여 sliver 파라메터에 위젯 리스트를 넘긴다. sliver에 넘겨지는 위젯 리스트들은 SliverAppBar()가 고정되는 해더의 역할을 하며 SliverList, SliverGrid와 같은 위젯을 다음 위치에 배치하면 된다. 즉 [해더, 내용, 해더, 내용] 형식으로 배치하여 사용할 수 있다.
CustomScrollView(
// (1) slivers에 위젯을 나열한다.
slivers: <Widget>[
// (2) Header인 SliverAppBar를 먼저 배치 후, 그 다음에 SliverList를 배치한다.
SliverAppBar(),
SliverList() // 또는 SliverFixedExtentList()
// (3) 순서대로 (2)번과 같은 내용을 차례대로 배열하면 멀티 stickyheader 구현이 가능하다.
//SliverAppBar(),
//SliverList() // 또는 SliverFixedExtentList()
...
],
));
다음은 예제의 전체소스이다.
import 'package:flutter/material.dart';
import 'dart:ui';
void main() => runApp(MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
static String _title = 'Flutter SliverAppBar test';
@override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.black,
scrollBehavior: DeskScrollBehavior(),
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final _pageController = PageController(viewportFraction: 1);
int _index = 0;
Widget _buildPageView() {
return Container(
color: Colors.black,
height: 100,
child: PageView.builder(
itemCount: 10,
controller: _pageController,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color: (index % 2 == 0)
? Color.fromARGB(255, 196, 15, 15)
: Color.fromARGB(255, 73, 73, 72),
child: SizedBox(
width: 100, child: Center(child: Text("${_index}"))),
),
);
},
onPageChanged: (int index) => setState(() => _index = index)),
);
}
Container _buildGridView() {
return Container(
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 5,
crossAxisSpacing: 5,
),
itemCount: 10,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
var url = (index % 2 == 0)
? "https://lh3.googleusercontent.com/GTmuiIZrppouc6hhdWiocybtRx1Tpbl52eYw4l-nAqHtHd4BpSMEqe-vGv7ZFiaHhG_l4v2m5Fdhapxw9aFLf28ErztHEv5WYIz5fA"
: "https://oopy.lazyrockets.com/api/v2/notion/image?src=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F9e5d9e8e-4b0d-4f3f-9580-baf556faad5c%2Fios-logo.jpg&blockId=d983bdda-9a22-4eab-998b-9a0ff3f8ec73&width=2400";
return Container(child: Image.network(url));
}),
);
}
Widget _buildHeader(String s, [Color c = Colors.white]) {
return Container(
width: double.infinity,
height: 100,
color: c,
child: Center(
child: Text(
s,
style: TextStyle(fontSize: 20, color: Colors.grey),
)));
}
late List<Widget> widgetList1;
@override
void initState() {
widgetList1 = [
_buildHeader("+Grid뷰"),
_buildGridView(),
_buildHeader("+Page뷰"),
for (var i = 0; i < 10; i++) _buildPageView(),
];
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter SliverAppBar test'),
),
body: CustomScrollView(
slivers: <Widget>[
// 첫번째 Header
SliverAppBar(
pinned: true,
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('🍕 Flex한 SliverAppBar', style: TextStyle(fontSize: 20)),
background: Image.network(fit: BoxFit.fill,"https://upload.wikimedia.org/wikipedia/commons/thumb/2/21/Desktop_Ubuntu_20.04.png/1024px-Desktop_Ubuntu_20.04.png"),
),
),
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
child: Text(
'🐈'.multiString(index),
style: TextStyle(fontSize: 30),
),
);
}, childCount: 10
),
),
// 두번째 해더
SliverAppBar(
pinned: true,
title: ListTile(
leading: Text("🍕",
style: TextStyle(fontSize: 20, color: Colors.white)),
title: Text(
"고정된 SliverAppBar",
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => widgetList1[index],
childCount: widgetList1.length),
),
],
));
}
}
// 웹과 desktop에서 모바일처럼 터치 스크롤 지원하기 위함
class DeskScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
extension on String {
String multiString(int n){
return this * n;
}
}
'Source code or Tip > Flutter & Dart' 카테고리의 다른 글
[dart] dart에서 null safety check을 위한 let, apply 적용 (0) | 2022.08.19 |
---|---|
[Flutter] Layoutbuilder를 이용한 반응형 UI (0) | 2022.08.15 |
[Flutter] ScrollView에서 이동시 item 위치찾기 (0) | 2022.08.12 |
[Flutter] InteractiveViewer를 listView안에 넣기 (0) | 2022.08.11 |
[Flutter link] Flutter 개발자 필수 사이트 정리 (0) | 2022.08.11 |
Comments