flutter如何实现分页器

在Flutter中如何实现一个分页器组件?目前需要在列表底部添加分页控件,支持上一页/下一页跳转和页码选择,最好能显示总页数和当前页数。有没有比较成熟的第三方库推荐?或者官方是否有提供现成的解决方案?希望能给出具体的代码示例和实现思路。

2 回复

Flutter中实现分页器常用ListView.builder结合ScrollController监听滚动事件。当滑动到底部时触发加载更多数据,更新数据列表即可。也可使用第三方库如flutter_infinite_list简化开发。

更多关于flutter如何实现分页器的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中实现分页器,可以通过以下几种方式:

1. 使用ListView + ScrollController

class PaginationExample extends StatefulWidget {
  @override
  _PaginationExampleState createState() => _PaginationExampleState();
}

class _PaginationExampleState extends State<PaginationExample> {
  final ScrollController _scrollController = ScrollController();
  List<String> items = [];
  int currentPage = 1;
  bool isLoading = false;
  bool hasMore = true;

  @override
  void initState() {
    super.initState();
    _loadInitialData();
    _scrollController.addListener(_scrollListener);
  }

  void _scrollListener() {
    if (_scrollController.position.pixels == 
        _scrollController.position.maxScrollExtent) {
      _loadMoreData();
    }
  }

  Future<void> _loadInitialData() async {
    setState(() => isLoading = true);
    // 模拟API调用
    await Future.delayed(Duration(seconds: 1));
    items = List.generate(20, (index) => 'Item ${index + 1}');
    setState(() => isLoading = false);
  }

  Future<void> _loadMoreData() async {
    if (isLoading || !hasMore) return;
    
    setState(() => isLoading = true);
    // 模拟API调用
    await Future.delayed(Duration(seconds: 1));
    
    final newItems = List.generate(20, 
        (index) => 'Item ${items.length + index + 1}');
    
    setState(() {
      items.addAll(newItems);
      isLoading = false;
      currentPage++;
      // 假设最多加载5页
      if (currentPage >= 5) hasMore = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('分页示例')),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              controller: _scrollController,
              itemCount: items.length + (hasMore ? 1 : 0),
              itemBuilder: (context, index) {
                if (index == items.length) {
                  return _buildLoader();
                }
                return ListTile(title: Text(items[index]));
              },
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildLoader() {
    return Padding(
      padding: EdgeInsets.all(16.0),
      child: Center(
        child: isLoading 
            ? CircularProgressIndicator()
            : Text(hasMore ? '加载更多...' : '没有更多数据'),
      ),
    );
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }
}

2. 使用第三方包(推荐)

安装 infinite_scroll_pagination 包:

dependencies:
  infinite_scroll_pagination: ^3.2.0

使用示例:

class PagedListViewExample extends StatefulWidget {
  @override
  _PagedListViewExampleState createState() => _PagedListViewExampleState();
}

class _PagedListViewExampleState extends State<PagedListViewExample> {
  static const _pageSize = 20;
  final PagingController<int, String> _pagingController = 
      PagingController(firstPageKey: 0);

  @override
  void initState() {
    _pagingController.addPageRequestListener((pageKey) {
      _fetchPage(pageKey);
    });
    super.initState();
  }

  Future<void> _fetchPage(int pageKey) async {
    try {
      final newItems = await _fakeApiCall(pageKey);
      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;
    }
  }

  Future<List<String>> _fakeApiCall(int startIndex) async {
    await Future.delayed(Duration(seconds: 1));
    return List.generate(_pageSize, 
        (index) => 'Item ${startIndex + index + 1}');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('分页列表')),
      body: PagedListView<int, String>(
        pagingController: _pagingController,
        builderDelegate: PagedChildBuilderDelegate<String>(
          itemBuilder: (context, item, index) => 
              ListTile(title: Text(item)),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _pagingController.dispose();
    super.dispose();
  }
}

关键要点

  1. 监听滚动位置:使用ScrollController检测是否滚动到底部
  2. 状态管理:跟踪加载状态、当前页码、是否有更多数据
  3. 性能优化:避免重复加载,合理设置分页大小
  4. 错误处理:网络请求失败时的重试机制

推荐使用第三方包 infinite_scroll_pagination,它提供了更完善的分页功能和更好的性能优化。

回到顶部