자동 항목 그룹화와 원활한 무한 로딩을 지원하는 동적이고 효율적인 스크롤 리스트를 가능하게 하는 플러터 패키지입니다. 사용자가 스크롤할 때만 보이는 항목만 렌더링하고, 지능적으로 추가 데이터를 가져오므로 성능을 최적화합니다. 대규모 데이터 세트에 대해 구조화된 표시와 플랫폼 간 부드러운 사용자 경험을 필요로 하는 경우에 이상적입니다.
사용 사례
그룹화된 콘텐츠를 포함한 대규모 데이터셋
실시간 피드 스크롤
동적 목록 페이징
지연 로딩을 갖춘 오프라인 우선 애플리케이션
콘텐츠가 풍부한 대시보드
주요 기능
자동 항목 그룹화
무결점 무한 스크롤
효율적인 메모리 사용
크로스 플랫폼 지원
사용자 지정 가능한 그룹 헤더
요청에 따라 데이터 로드
적합한 대상
확장 가능한 리스트 인터페이스를 구축하는 개발자
광범위한 데이터 세트를 가진 앱
반응형 UI가 필요한 프로젝트
다양한 플랫폼을 대상으로 하는 팀
최적화된 성능이 필요한 사용자
고려 사항
비동기 데이터 소스를 올바르게 처리해야 합니다
복잡한 그룹 규칙을 위해 사용자 정의 로직이 필요할 수 있습니다
정적이고 작은 목록에는 적합하지 않음
정확한 상태 관리에 의존함
스트림 또는 미래 기반 데이터 공급자와 가장 잘 어울립니다
원본 README
연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.
Show some love by dropping a ⭐ at GitHub
Infinite Grouped List
Brings together infinite scrolling, group-based item organization, and numerous other enhancements to improve the end-user experience.
Key Features
Infinite Scrolling: The widget supports loading more data as the user reaches the end of the list. This is essential for handling large datasets without overwhelming the user or their device.
Grouping of Items: The widget can organize items into groups based on user-defined criteria. This helps to make sense of large amounts of data by breaking it down into manageable chunks.
Reactive State Management: 🆕 Full support for modern state management patterns like BLoC, Provider, and Riverpod with dedicated reactive constructors that separate event triggering from data listening.
Customizable Loading and Error States: You can provide custom widgets to be displayed while data is being loaded or if an error occurs. This allows for a seamless, branded experience.
Pull-to-Refresh: The widget incorporates a pull-to-refresh feature, letting users manually trigger a refresh of the list's content.
Sticky Group Headers: Headers stick to the top of the list as the user scrolls, making it easier to understand the context of the data they're viewing. Can be changed.
Group Anchoring: Opt-in jump-to-group support lets you instantly scroll to any group (for example "Today") through the controller without impacting base performance.
Usage
The InfiniteGroupedList offers two usage patterns to fit different architectural approaches:
🔄 Reactive Pattern (Recommended for Modern Apps)
Perfect for apps using BLoC, Provider, Riverpod, or any external state management:
Reactive: Event triggering and data listening are completely separated. Your state management handles data fetching, and the widget displays the current state.
Imperative: The widget directly calls your data fetching function and manages the loading states internally.
PaginationInfo Helper
When using the imperative pattern, PaginationInfo provides pagination context:
offset: Current item offset for offset-based pagination
page: Current page number for page-based pagination
limit: Items per page (configurable via controller)
The InfiniteGroupedList widget is a comprehensive solution for any use case that involves displaying large amounts of data in an organized, easy-to-navigate manner.
Jumping to a Group
Need to anchor the list to a specific group (e.g. "Today")? Enable anchoring on the widget and invoke the new controller helper:
final controller = InfiniteGroupedListController<Transaction, DateTime, String>();
InfiniteGroupedList(
enableAnchoring: true,
controller: controller,
// ... other params
);
// Later, jump to a concrete title or resolve it dynamically with a predicate// Option A: jump by the exact group title you already know
controller.jumpToGroup(
title: 'Today',
alignment: 0.0, // pin the header to the top
);
// Option B: resolve dynamically via predicate (provide predicate *instead* of title)
controller.jumpToGroup(
predicate: (title, groupBy) => isSameDay(groupBy, DateTime.now()),
alignment: 0.0,
loadUntilFound: true, // imperative mode only
maxRetries: 3,
);
Anchoring is opt-in, so you only incur the tiny bookkeeping cost when you actually need the feature. The optional loadUntilFound flag is available in imperative mode; reactive consumers should trigger their own data loads before retrying the jump. When loadUntilFound is enabled, maxRetries limits the extra page loads attempted and defaults to 3.
Examples
Explore comprehensive examples demonstrating different usage patterns:
🆕 Reactive BLoC Example: Complete implementation using reactive pattern with flutter_bloc, including error handling, loading states, and event-driven architecture.
🎯 Jump to Group Example: Demonstrates enabling anchoring plus controller.jumpToGroup() to instantly scroll to the "Today" section.
📅 Group by Date: Traditional imperative pattern grouping transactions by date with custom group titles.
🏷️ Group by Type: Demonstrates grouping items by category/type with different visual treatments.
🔲 Grid Layout: Shows how to use the .gridView() constructor for grid-based layouts.
Run the example app to see all patterns in action with an interactive example selection screen.
Git Hook
To block pushes when the package does not analyze or test cleanly, install the
repo-local pre-push hook once:
./tool/install_git_hooks.sh
The hook runs:
fvm flutter analyze
fvm flutter test
Migration Guide
Version 1.4.0 note: The misspelled seperatorBuilder parameter was removed. Use separatorBuilder instead.
Existing users: If you were not using the misspelled separator parameter, your code continues to work without any further changes.
Moving to reactive pattern:
Replace InfiniteGroupedList() with InfiniteGroupedList.reactive()
Move your onLoadMore logic to your state management solution
Replace the onLoadMore parameter with onLoadMoreTriggered callback
Provide external state via items, isLoading, hasReachedMax parameters
The reactive pattern is recommended for new projects using modern state management, while the imperative pattern remains fully supported for simpler use cases.