Pagination and Infinite Lists
When you need to display large lists of data from an API, loading everything at once is rarely practical. APIs often provide pagination—a way to fetch data in chunks or "pages"—so your app only loads and displays a limited number of items at a time. This approach is essential for performance, usability, and network efficiency, especially when dealing with thousands of records.
main.dart
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100import 'package:flutter/material.dart'; import 'dart:async'; import 'dart:math'; void main() { runApp(PaginatedListApp()); } class PaginatedListApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Pagination Demo', home: PaginatedListScreen(), ); } } class PaginatedListScreen extends StatefulWidget { @override _PaginatedListScreenState createState() => _PaginatedListScreenState(); } class _PaginatedListScreenState extends State<PaginatedListScreen> { final ScrollController _scrollController = ScrollController(); final List<String> _items = []; bool _isLoading = false; int _currentPage = 1; final int _pageSize = 20; bool _hasMore = true; @override void initState() { super.initState(); _fetchPage(); _scrollController.addListener(_onScroll); } @override void dispose() { _scrollController.dispose(); super.dispose(); } Future<List<String>> _fetchData(int page, int pageSize) async { // Simulate API delay await Future.delayed(Duration(seconds: 2)); // Simulate total 100 items in API int totalItems = 100; int start = (page - 1) * pageSize; if (start >= totalItems) return []; int end = min(start + pageSize, totalItems); return List.generate(end - start, (i) => 'Item �24{start + i + 1}'); } void _fetchPage() async { if (_isLoading || !_hasMore) return; setState(() { _isLoading = true; }); List<String> newItems = await _fetchData(_currentPage, _pageSize); setState(() { _items.addAll(newItems); _isLoading = false; _hasMore = newItems.length == _pageSize; if (_hasMore) _currentPage++; }); } void _onScroll() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200 && !_isLoading && _hasMore) { _fetchPage(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Paginated List')), body: ListView.builder( controller: _scrollController, itemCount: _items.length + (_isLoading || _hasMore ? 1 : 0), itemBuilder: (context, index) { if (index < _items.length) { return ListTile(title: Text(_items[index])); } else if (_hasMore || _isLoading) { return Padding( padding: const EdgeInsets.all(16.0), child: Center(child: CircularProgressIndicator()), ); } return SizedBox.shrink(); }, ), ); } }
To avoid duplicate API calls during infinite scrolling, always check if a request is already in progress before starting a new one. Use a flag like '_isLoading' to prevent multiple simultaneous requests, which can lead to repeated data or wasted bandwidth.
The code above demonstrates a paginated ListView that fetches more items from a simulated API as you scroll. A ScrollController listens for the user's scroll position. When the user nears the end of the list, the controller triggers another API call to fetch the next page. The _currentPage variable keeps track of which page to request next, and _hasMore ensures that fetching stops when all data has been loaded. This pattern efficiently loads new items only as needed, providing a smooth infinite scrolling experience.
Kiitos palautteestasi!
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme
Mahtavaa!
Completion arvosana parantunut arvoon 6.67
Pagination and Infinite Lists
Pyyhkäise näyttääksesi valikon
When you need to display large lists of data from an API, loading everything at once is rarely practical. APIs often provide pagination—a way to fetch data in chunks or "pages"—so your app only loads and displays a limited number of items at a time. This approach is essential for performance, usability, and network efficiency, especially when dealing with thousands of records.
main.dart
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100import 'package:flutter/material.dart'; import 'dart:async'; import 'dart:math'; void main() { runApp(PaginatedListApp()); } class PaginatedListApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Pagination Demo', home: PaginatedListScreen(), ); } } class PaginatedListScreen extends StatefulWidget { @override _PaginatedListScreenState createState() => _PaginatedListScreenState(); } class _PaginatedListScreenState extends State<PaginatedListScreen> { final ScrollController _scrollController = ScrollController(); final List<String> _items = []; bool _isLoading = false; int _currentPage = 1; final int _pageSize = 20; bool _hasMore = true; @override void initState() { super.initState(); _fetchPage(); _scrollController.addListener(_onScroll); } @override void dispose() { _scrollController.dispose(); super.dispose(); } Future<List<String>> _fetchData(int page, int pageSize) async { // Simulate API delay await Future.delayed(Duration(seconds: 2)); // Simulate total 100 items in API int totalItems = 100; int start = (page - 1) * pageSize; if (start >= totalItems) return []; int end = min(start + pageSize, totalItems); return List.generate(end - start, (i) => 'Item �24{start + i + 1}'); } void _fetchPage() async { if (_isLoading || !_hasMore) return; setState(() { _isLoading = true; }); List<String> newItems = await _fetchData(_currentPage, _pageSize); setState(() { _items.addAll(newItems); _isLoading = false; _hasMore = newItems.length == _pageSize; if (_hasMore) _currentPage++; }); } void _onScroll() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200 && !_isLoading && _hasMore) { _fetchPage(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Paginated List')), body: ListView.builder( controller: _scrollController, itemCount: _items.length + (_isLoading || _hasMore ? 1 : 0), itemBuilder: (context, index) { if (index < _items.length) { return ListTile(title: Text(_items[index])); } else if (_hasMore || _isLoading) { return Padding( padding: const EdgeInsets.all(16.0), child: Center(child: CircularProgressIndicator()), ); } return SizedBox.shrink(); }, ), ); } }
To avoid duplicate API calls during infinite scrolling, always check if a request is already in progress before starting a new one. Use a flag like '_isLoading' to prevent multiple simultaneous requests, which can lead to repeated data or wasted bandwidth.
The code above demonstrates a paginated ListView that fetches more items from a simulated API as you scroll. A ScrollController listens for the user's scroll position. When the user nears the end of the list, the controller triggers another API call to fetch the next page. The _currentPage variable keeps track of which page to request next, and _hasMore ensures that fetching stops when all data has been loaded. This pattern efficiently loads new items only as needed, providing a smooth infinite scrolling experience.
Kiitos palautteestasi!