앱을 사용할 때 스크롤 동작은 정말 흔히 볼 수 있어요. 뉴스 앱에서 아래로 당기면 화면이 갱신되거나, 쇼핑 앱에서 무한히 스크롤을 내리면 새로운 상품이 계속 나타나는 것처럼요. 스크롤은 단순히 콘텐츠를 넘기는 역할뿐만 아니라, 특정한 기능을 구현하는 데에도 많이 활용돼요. 이번 글에서는 Flutter로 앱을 만들 때 자주 사용되는 스크롤 관련 기능 몇 가지를 다뤄볼 거예요.
스크롤 관련 메서드와 속성 이해하기
Flutter에서는 스크롤을 감지하고 제어하기 위해 다양한 방법을 제공하는데, 가장 기본이 되는 것이 바로 ScrollController예요. ScrollController를 사용하면 현재 스크롤된 위치를 알 수 있고, 스크롤 이벤트를 감지해서 다양한 액션을 취할 수도 있어요.
예를 들어, 현재 스크롤 위치를 알고 싶다면 다음과 같이 코드를 작성할 수 있어요.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ScrollExample(),
);
}
}
class ScrollExample extends StatefulWidget {
@override
_ScrollExampleState createState() => _ScrollExampleState();
}
class _ScrollExampleState extends State<ScrollExample> {
final ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
_scrollController.addListener(() {
print("현재 스크롤 위치: ${_scrollController.position.pixels}");
print("최대 스크롤 가능 위치: ${_scrollController.position.maxScrollExtent}");
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("스크롤 위치 예제")),
body: ListView.builder(
controller: _scrollController,
itemCount: 50,
itemBuilder: (context, index) {
return ListTile(title: Text("아이템 $index"));
},
),
);
}
}
이 코드를 실행하면 스크롤할 때마다 현재 스크롤 위치와 최대 스크롤 가능 위치가 출력돼요. 이런 정보를 이용하면 특정 위치에서 특정 기능을 동작시킬 수도 있겠죠?
스크롤 방향에 따라 하단 탭 숨기고 보이기
이번에는 좀 더 실제적인 예시로, 사용자가 화면을 위로 스크롤할 때는 하단의 탭이 숨겨지고, 아래로 스크롤하면 다시 나타나는 기능을 구현해볼게요. 이 기능을 통해 콘텐츠를 더 넓은 화면에서 볼 수 있도록 도와줄 수 있어요.
아래의 예시를 실행해보면 기능을 더 직관적으로 이해할 수 있을 거예요.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ScrollHideTabExample(),
);
}
}
class ScrollHideTabExample extends StatefulWidget {
@override
_ScrollHideTabExampleState createState() => _ScrollHideTabExampleState();
}
class _ScrollHideTabExampleState extends State<ScrollHideTabExample> {
final ScrollController _scrollController = ScrollController();
bool _isTabVisible = true;
double _previousOffset = 0;
@override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels > _previousOffset && _isTabVisible) {
setState(() {
_isTabVisible = false; // 아래로 스크롤하면 탭 숨김
});
} else if (_scrollController.position.pixels < _previousOffset) {
setState(() {
_isTabVisible = true; // 위로 스크롤하면 탭 다시 보이기
});
}
_previousOffset = _scrollController.position.pixels;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("스크롤 탭 숨기기")),
body: ListView.builder(
controller: _scrollController,
itemCount: 50,
itemBuilder: (context, index) {
return ListTile(title: Text("리스트 아이템 $index"));
},
),
bottomNavigationBar: AnimatedContainer(
duration: Duration(milliseconds: 300),
height: _isTabVisible ? 60 : null, // `null`로 설정하여 공간을 없앰
child: _isTabVisible
? BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '홈'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: '검색'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: '프로필'),
],
)
: SizedBox.shrink(), // 완전히 숨기기
),
);
}
}
이 코드의 핵심은 스크롤 방향에 따라 _isTabVisible의 값을 바꿔주는 거예요. 이를 통해 사용자의 스크롤 동작에 따라 하단의 탭바를 자연스럽게 숨기거나 보이게 할 수 있어요.
무한 스크롤 구현하기
무한 스크롤은 뉴스 앱이나 쇼핑몰처럼 콘텐츠가 많고 계속 로딩될 필요가 있을 때 유용하게 사용할 수 있어요. 사용자가 화면의 끝부분에 도달하면 자동으로 새로운 데이터를 불러와 계속해서 콘텐츠를 볼 수 있도록 해주는 기능이에요. Flutter에서 이 기능을 구현하려면 ScrollController의 위치를 감지해서, 화면 끝부분에 다다랐을 때 추가적인 데이터를 로딩하도록 하면 돼요.
다음은 가장 간단하게 무한 스크롤을 구현하는 코드예요.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: InfiniteScrollExample(),
);
}
}
class InfiniteScrollExample extends StatefulWidget {
@override
_InfiniteScrollExampleState createState() => _InfiniteScrollExampleState();
}
class _InfiniteScrollExampleState extends State<InfiniteScrollExample> {
final ScrollController _scrollController = ScrollController();
List<int> _items = List.generate(20, (index) => index); // 초기 데이터
bool _isLoading = false;
@override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 100 && !_isLoading) {
_loadMoreItems(); // 화면 끝에 가까워지면 추가 로딩
}
});
}
void _loadMoreItems() {
setState(() => _isLoading = true);
Future.delayed(Duration(seconds: 2), () {
setState(() {
_items.addAll(List.generate(20, (index) => _items.length + index)); // 추가 데이터
_isLoading = false;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('무한 스크롤 예제')),
body: ListView.builder(
controller: _scrollController,
itemCount: _items.length + 1,
itemBuilder: (context, index) {
if (index == _items.length) {
return _isLoading
? Padding(
padding: const EdgeInsets.all(16.0),
child: Center(child: CircularProgressIndicator()),
)
: SizedBox.shrink();
}
return ListTile(title: Text('아이템 ${_items[index]}'));
},
),
);
}
}
이 코드의 핵심은 사용자가 스크롤의 끝부분에 다다랐을 때 추가 데이터를 로딩하도록 설정하는 부분이에요. 이 방법으로 사용자는 화면을 내릴 때마다 더 많은 콘텐츠를 자동으로 볼 수 있어서 매우 편리해져요. 위의 예제에서는 실제 상황과 유사하게 만들기 위해서 로딩 시간을 2초로 설정했어요.
마치며...
지금까지 Flutter에서 사용자의 스크롤 동작을 이용해 다양한 기능을 구현하는 방법을 알아봤어요. 스크롤 위치를 확인하거나, 사용자의 스크롤 방향에 따라 탭을 숨기거나 보이게 만들고, 무한히 데이터를 불러오는 무한 스크롤까지 구현할 수 있었죠. 이런 기능들을 잘 활용하면 앱의 사용성을 높이고, 더욱 풍성한 사용자 경험을 제공할 수 있어요. 여러분도 이 방법들을 응용해서 더욱 멋진 앱을 만들어 보세요!
'IT' 카테고리의 다른 글
Dart로 간단한 쇼핑 기능 구현하기 (2) | 2025.03.14 |
---|---|
플러터 Provider 사용법 (0) | 2025.03.13 |
플러터에서 하단 탭 만들기 (0) | 2025.03.11 |
플러터에서 State 활용하기 (0) | 2025.03.08 |
[UXUI][프론트엔드] 플러터 위젯으로 레이아웃 만들기(2) (0) | 2025.03.07 |