무한 스크롤 위젯은 대용량 데이터 세트를 탐색할 때 원활한 사용자 경험을 제공하기 위해 SNS서비스 등에서 널리 사용되는 기술입니다.
pub.dev의 Flutter Favorite 패키지인 infinite_scroll_pagination 패키지를 통해 적용하는 방법을 알아보겠습니다.
사용방법은 간단합니다.
스크롤이 특정 위치(마지막)에 도달하면 자동으로 pagination이 가능한 api에서 지속적으로 다음 페이지의 데이터를 가져와서 child에 추가해주는 코드입니다.
pagination이 가능한 api에서 데이터를 가져오는 함수를 추가해줍니다.
static const _pageSize = 20;
Future<void> _fetchPage(int pageKey) async {
try {
final newItems = await RemoteApi.getCharacterList(pageKey, _pageSize);
final isLastPage = newItems.length < _pageSize;
if (isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + newItems.length;
_pagingController.appendPage(newItems, nextPageKey);
}
} catch (error) {
_pagingController.error = error;
}
}
_fetchPage 함수에서는 appendPage()를 이용해서 데이터를 지속적으로 추가해주고, 마지막 페이지일 경우에는 가져온 데이터의 갯수와 한 페이지에 들어갈 아이템의 수로 비교해서 appendLastPage() 함수를 이용해서 넣어줍니다.
final PagingController<int, CharacterSummary> _pagingController =
PagingController(firstPageKey: 0);
@override
void initState() {
_pagingController.addPageRequestListener((pageKey) {
_fetchPage(pageKey);
});
super.initState();
}
그리고 scroll을 감지하는 controller에 fetch 함수를 추가해줍니다.
pageKey는 가져온 전체 데이터의 갯수와 동일하도록 작성되어 있습니다. 처음에는 api에 0이 입력되고 마지막 페이지가 아니라면 20씩(_pageSize) 증가합니다. 만약 api에서 page를 요청하는 방법이 다를 경우 추가로 작업이 필요합니다.
마지막으로 스크롤이 가능한 페이지 위젯을 정의해줍니다.
PagedListView<int, CharacterSummary>(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<CharacterSummary>(
itemBuilder: (context, item, index) => CharacterListItem(
character: item,
),
),
);
플러터의 기본적인 스크롤 위젯들과 동일한 구조로 되어있습니다.
scroll 동작에 대한 컨트롤러(PagingController)와
해당 스크롤 위젯에 그려질 Child를 builderDelegate에서 정의합니다.
PagedListView.separated(
builderDelegate: PagedChildBuilderDelegate<RaffleHistoryItemModel>(
itemBuilder: (context, item, index) => RaffleHistoryTile(item: item),
pagingController: _pagingController,
separatorBuilder: (BuildContext context, int index) => Divider(
height: 1,
color: Colors.grey2,
),
);
.separated를 이용해서 아이템을 구분하는 Divider를 넣어 줄 수도 있습니다.