Flutter中ListView无限滚动异常及分页实现求助
Hey there! Let's tackle your Flutter/Dart questions and fix those issues you're facing, step by step.
To display exactly 100 items in a ListView, the key is to set an explicit itemCount for ListView.builder—this tells Flutter to only render those 100 items, preventing infinite scrolling. Also, make sure your data source has at least 100 entries to avoid index errors.
Example Code:
// Generate a sample data list with 100 items final List<String> data = List.generate(100, (index) => 'Item ${index + 1}'); ListView.builder( itemCount: data.length, // Use the data list length to fix item count itemBuilder: (context, index) { // Index ranges from 0 to 99, perfectly matching our 100-item list return ListTile( title: Text(data[index]), ); }, )
If you don't have a pre-generated list, you can directly set itemCount: 100 and generate content on the fly in itemBuilder—just ensure you don't try to access an out-of-bounds index.
Pagination works by loading the first page initially, then triggering the next page load when the user scrolls near the bottom of the list. We'll use a ScrollController to track scroll position, plus state variables to manage loading status and remaining data.
Example Code:
class PaginatedListScreen extends StatefulWidget { @override _PaginatedListScreenState createState() => _PaginatedListScreenState(); } class _PaginatedListScreenState extends State<PaginatedListScreen> { final ScrollController _scrollController = ScrollController(); List<String> _items = []; int _currentPage = 1; final int _pageSize = 20; // 20 items per page (total 5 pages = 100 items) bool _isLoading = false; bool _hasMoreItems = true; @override void initState() { super.initState(); _loadFirstPage(); _scrollController.addListener(_checkScrollPosition); } @override void dispose() { _scrollController.dispose(); super.dispose(); } // Load first page data (simulate API call) Future<void> _loadFirstPage() async { setState(() => _isLoading = true); await Future.delayed(const Duration(seconds: 1)); // Simulate network delay final newItems = List.generate(_pageSize, (i) => 'Page 1 - Item ${i + 1}'); setState(() { _items = newItems; _isLoading = false; }); } // Load next page data Future<void> _loadNextPage() async { if (_isLoading || !_hasMoreItems) return; // Prevent duplicate loads setState(() => _isLoading = true); await Future.delayed(const Duration(seconds: 1)); final nextPage = _currentPage + 1; // Stop loading once we hit 100 total items if (_items.length + _pageSize > 100) { final remainingItems = 100 - _items.length; final newItems = List.generate(remainingItems, (i) => 'Page $nextPage - Item ${i + 1}'); setState(() { _items.addAll(newItems); _hasMoreItems = false; _isLoading = false; }); return; } final newItems = List.generate(_pageSize, (i) => 'Page $nextPage - Item ${i + 1}'); setState(() { _items.addAll(newItems); _currentPage = nextPage; _isLoading = false; }); } // Trigger next page load when near bottom void _checkScrollPosition() { final nearBottom = _scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200; // 200px from bottom if (nearBottom) _loadNextPage(); } @override Widget build(BuildContext context) { return ListView.builder( controller: _scrollController, // Add 1 extra item for loading/no-more-data indicator itemCount: _items.length + (_isLoading || _hasMoreItems ? 1 : 0), itemBuilder: (context, index) { if (index == _items.length) { // Render loading indicator or "no more data" message if (_isLoading) { return const Center(child: CircularProgressIndicator()); } else if (!_hasMoreItems) { return const Center(child: Text('No more items to load!')); } return const SizedBox.shrink(); } return ListTile(title: Text(_items[index])); }, ); } }
Issue 1: Infinite Scrolling at the Bottom of ListView
This happens because you didn't set a proper itemCount for your ListView.builder. Without itemCount, Flutter assumes there are infinite items and keeps calling itemBuilder as you scroll.
Fix:
- For fixed 100 items: Set
itemCount: 100(or your data list length) - For pagination: Use
itemCount: _items.length + (_isLoading || _hasMoreItems ? 1 : 0)as shown in the pagination example
Issue 2: RangeError (index): Invalid value: Not in range 0..99, inclusive: 100
This error means you're trying to access index 100, but your data list only has 100 items (valid indices 0-99). Common causes:
itemCountis set to a value larger than your data list length- Pagination logic doesn't stop loading once you hit 100 total items
Fix:
- Ensure
itemCountnever exceeds your data list's actual length (for fixed lists) - In pagination, add a check to stop loading when
_items.length >= 100(like in the pagination example above), and set_hasMoreItems = falseso no extra items are added toitemCount
内容的提问来源于stack exchange,提问作者Paresh Mayani

