다트에서 커스텀 스크롤(Custom Scroll) 구현 방법은?
_____1. Q: “커스텀 스크롤”이란 무엇인가요?
A: Flutter에서 기본 제공되는 ListView·GridView 대신 Sliver(슬리버)를 기반으로 스크롤 영역을 직접 구성하고 물리(ScrollPhysics), 스크롤바 모양, 오버스크롤 효과 등을 세밀히 제어하는 기법입니다.
2. Q: CustomScrollView와 Sliver의 관계는?
A: CustomScrollView는 여러 Sliver 위젯을 한 데 묶어 스크롤 가능한 영역을 만듭니다. SliverAppBar, SliverList, SliverGrid, SliverToBoxAdapter 등을 조합해 복합 레이아웃을 구현할 수 있습니다.
3. Q: 기본 ListView 대신 CustomScrollView를 사용하려면?
A:
```dart
CustomScrollView(
slivers: [
SliverAppBar(
title: Text('커스텀 스크롤 예제'),
floating: true,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(title: Text('아이템 $index')),
childCount: 50,
),
),
],
)
```
- SliverAppBar: 스크롤에 따라 축소/고정되는 앱 바
- SliverList: 일반 리스트
- SliverGrid: 그리드 형태
4. Q: ScrollController로 스크롤 위치를 제어하려면?
A:
```dart
final controller = ScrollController();
// 위젯
CustomScrollView(
controller: controller,
slivers: [/* ... */],
);
// 특정 위치로 이동
controller.animateTo(
200.0,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
```
- scrollController.position.pixels 읽기
- listener 등록: controller.addListener(...)
5. Q: ScrollPhysics를 커스터마이징하려면?
A:
```dart
class BouncingScrollPhysicsAndroid extends BouncingScrollPhysics {
@override
BouncingScrollPhysics applyTo(ScrollPhysics ancestor) {
return BouncingScrollPhysicsAndroid(parent: buildParent(ancestor));
}
@override
double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
// offset 조정 로직
return super.applyPhysicsToUserOffset(position, offset * 0.5);
}
}
// 적용
CustomScrollView(
physics: BouncingScrollPhysicsAndroid(),
slivers: [/* ... */],
);
```
6. Q: ScrollBehavior를 바꿔 오버스크롤·글리프 효과를 제어하려면?
A:
```dart
class NoGlowScrollBehavior extends ScrollBehavior {
@override
Widget buildViewportChrome(
BuildContext context, Widget child, AxisDirection axisDirection) {
return child; // 글리프(흔들림) 제거
}
}
// 최상위 적용
MaterialApp(
scrollBehavior: NoGlowScrollBehavior(),
home: /* ... */,
);
```
7. Q: 커스텀 스크롤바(Custom Scrollbar) 추가 방법은?
A:
```dart
Scrollbar(
controller: controller,
thumbVisibility: true, // 항상 보이기(2.0.0+)
thickness: 6,
radius: Radius.circular(3),
child: CustomScrollView(
controller: controller,
slivers: [/* ... */],
),
);
```
- thumbVisibility: 스크롤바 상시 표시
- thickness·radius로 모양 변경
8. Q: SliverToBoxAdapter 사용 예제는?
A: 고정 높이 위젯을 슬리버에 삽입할 때 사용합니다.
```dart
SliverToBoxAdapter(
child: Container(
height: 150,
color: Colors.blueAccent,
child: Center(child: Text('커스텀 배너')),
),
),
```
A: FutureBuilder·StreamBuilder 등으로 데이터를 불러온 뒤 SliverChildListDelegate를 사용해 리스트 갱신:
```dart
SliverList(
delegate: SliverChildListDelegate(
items.map((item) => ListTile(title: Text(item))).toList(),
),
)
```
10. Q: 성능 최적화 팁은?
A:
- SliverChildBuilderDelegate 사용: 화면에 보이는 아이템만 렌더링
- const 생성자 활용: 위젯 재생성 최소화
- keepAlive(using AutomaticKeepAliveClientMixin)로 복잡한 자식 위젯 재생성 방지
- 이미지 캐싱: CachedNetworkImage 등 활용
11. Q: 자주 발생하는 오류 및 해결책은?
A:
- “ScrollController not attached” 오류: ListView/CustomScrollView에 controller 등록 여부 확인
- Nested Scroll 충돌: primary: false, shrinkWrap: true 옵션 검토
- Sliver 위젯을 직접 자식으로 쓰지 않을 때: SliverToBoxAdapter로 감싸기
12. Q: 예제 전체 코드 (기본 뼈대)
A:
```dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
scrollBehavior: NoGlowScrollBehavior(),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State
final ScrollController _controller = ScrollController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Scrollbar(
controller: _controller,
thumbVisibility: true,
child: CustomScrollView(
controller: _controller,
physics: BouncingScrollPhysicsAndroid(),
slivers: [
SliverAppBar(
title: Text('커스텀 스크롤 예제'),
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
'https://picsum.photos/400/200',
fit: BoxFit.cover,
),
),
pinned: true,
),
SliverToBoxAdapter(
child: Container(
height: 100,
color: Colors.amber,
child: Center(child: Text('배너 섹션')),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(title: Text('아이템 $index')),
childCount: 30,
),
),
],
),
),
);
}
}
// 글로우 제거
class NoGlowScrollBehavior extends ScrollBehavior {
@override
Widget buildViewportChrome(
BuildContext context, Widget child, AxisDirection axisDirection) {
return child;
}
}
// 물리 효과 커스텀
class BouncingScrollPhysicsAndroid extends BouncingScrollPhysics {
BouncingScrollPhysicsAndroid({ScrollPhysics? parent})
: super(parent: parent);
@override
BouncingScrollPhysicsAndroid applyTo(ScrollPhysics? ancestor) {
return BouncingScrollPhysicsAndroid(parent: buildParent(ancestor));
}
@override
double applyPhysicsToUserOffset(
ScrollMetrics position, double offset) {
// 범위 내로만 반동 폭 제한
return super.applyPhysicsToUserOffset(position, offset * 0.7);
}
}
```
— 끝 —
Flutter는 스크롤 가능한 위젯을 쉽게 만들 수 있도록 다양한 도구를 제공합니다.
여기서는 Flutter의 `CustomScrollView`와 `Sliver` 위젯을 사용하여 커스텀 스크롤을 구현하는 방법에 대해 자세히 설명하겠습니다.
1. CustomScrollView 이해하기 `CustomScrollView`는 여러 개의 스크롤 가능한 위젯을 조합하여 사용할 수 있는 위젯입니다.
이 위젯은 스크롤 방향에 따라 다양한 슬리버(Sliver) 위젯을 포함할 수 있습니다.
슬리버는 스크롤 가능한 영역을 정의하는 위젯으로, 스크롤 시 동적으로 크기와 위치를 조정할 수 있습니다.
2. Sliver 위젯 종류 - SliverAppBar : 스크롤 시 확장 및 축소되는 앱 바를 제공합니다.
- SliverList : 리스트 형태의 스크롤 가능한 영역을 제공합니다.
- SliverGrid : 그리드 형태의 스크롤 가능한 영역을 제공합니다.
- SliverToBoxAdapter : 일반 위젯을 슬리버로 감싸서 사용할 수 있게 해줍니다.
3. CustomScrollView 구현하기 아래는 `CustomScrollView`와 여러 슬리버를 사용하여 커스텀 스크롤을 구현하는 예제입니다.
```dart import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: CustomScrollViewExample(), ), ); } } class CustomScrollViewExample extends StatelessWidget { @override Widget build(BuildContext context) { return CustomScrollView( slivers:
4. 코드 설명 - SliverAppBar : 이 위젯은 스크롤 시 확장 및 축소되는 앱 바를 생성합니다.
`expandedHeight` 속성으로 최대 높이를 설정하고, `FlexibleSpaceBar`를 사용하여 배경 이미지와 제목을 설정합니다.
- SliverList : `SliverChildBuilderDelegate`를 사용하여 동적으로 리스트 항목을 생성합니다.
`childCount` 속성으로 생성할 항목의 수를 지정합니다.
5. 추가적인 커스터마이징 - SliverGrid : 그리드 형태의 레이아웃을 추가하고 싶다면 `SliverGrid`를 사용할 수 있습니다.
예를 들어, 이미지 그리드를 만들 수 있습니다.
- ScrollController : 스크롤 위치를 제어하거나 감지하기 위해 `ScrollController`를 사용할 수 있습니다.
이를 통해 스크롤 이벤트에 따라 특정 동작을 수행할 수 있습니다.
6. 성능 최적화 - Lazy Loading : `SliverChildBuilderDelegate`를 사용하면 필요한 항목만 생성하므로 메모리 사용을 최적화할 수 있습니다.
- Caching : 이미지와 같은 리소스를 캐싱하여 성능을 향상시킬 수 있습니다.
7. Flutter의 `CustomScrollView`와 슬리버 위젯을 사용하면 다양한 스크롤 효과와 레이아웃을 쉽게 구현할 수 있습니다.
이를 통해 사용자에게 매력적이고 동적인 UI를 제공할 수 있습니다.
위의 예제를 바탕으로 필요에 따라 다양한 슬리버를 조합하여 커스텀 스크롤을 구현해 보세요.
작성자:
김하은 [비회원]
| 작성일자: 1년 전
2024-09-19 01:52:47
조회수: 104 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
조회수: 104 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
내용이 부정확하다면 싫어요를 클릭해주세요.