You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中点击按钮实现ListView/GridView无限加载更多数据

Flutter 实现点击加载更多 + 无限滚动列表方案

你要实现的类似生命线游戏的对话流式追加展示效果,核心是通过滚动监听+状态维护实现,ListView和GridView逻辑通用,具体实现如下:

Lifeline游戏效果参考


核心实现思路

  • 挂载ScrollController监听列表滚动位置,距离底部阈值小于设定值时自动触发加载(无限滚动效果)
  • 列表尾部固定预留1个位置,根据加载状态展示「加载更多按钮」/「加载中指示器」/「无更多数据提示」
  • 维护加载状态锁,避免重复触发数据请求
  • 新数据追加完成后自动滚动到列表底部,匹配流式内容的展示体验

完整实现代码

import 'package:flutter/material.dart';

class InfiniteScrollListPage extends StatefulWidget {
  const InfiniteScrollListPage({super.key});

  @override
  State<InfiniteScrollListPage> createState() => _InfiniteScrollListPageState();
}

class _InfiniteScrollListPageState extends State<InfiniteScrollListPage> {
  // 滚动控制器
  final ScrollController _scrollController = ScrollController();
  // 列表数据源
  final List<String> _dataList = [];
  // 加载状态锁
  bool _isLoading = false;
  // 是否还有更多数据
  bool _hasMore = true;
  // 模拟分页页码
  int _page = 1;
  // 单页加载数量
  final int _pageSize = 10;

  @override
  void initState() {
    super.initState();
    // 初始化加载第一页数据
    _loadMoreData();
    // 绑定滚动监听
    _scrollController.addListener(_scrollListener);
  }

  // 滚动监听,实现无限滚动
  void _scrollListener() {
    // 距离底部200像素时触发加载,提前加载提升体验
    if (_scrollController.position.pixels >=
            _scrollController.position.maxScrollExtent - 200 &&
        !_isLoading &&
        _hasMore) {
      _loadMoreData();
    }
  }

  // 模拟加载数据(替换为你的实际接口请求逻辑即可)
  Future<void> _loadMoreData() async {
    if (_isLoading) return;
    setState(() {
      _isLoading = true;
    });

    // 模拟网络请求延迟
    await Future.delayed(const Duration(seconds: 1));

    // 模拟最多加载5页数据,实际场景根据接口返回判断是否还有更多
    if (_page > 5) {
      setState(() {
        _hasMore = false;
        _isLoading = false;
      });
      return;
    }

    // 生成新数据
    final List<String> newData =
        List.generate(_pageSize, (index) => '第$_page页 第${index + 1}条内容');

    setState(() {
      _dataList.addAll(newData);
      _page++;
      _isLoading = false;
    });

    // 数据加载完成后滚动到底部,适配对话流场景
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_scrollController.hasClients) {
        _scrollController.animateTo(
          _scrollController.position.maxScrollExtent,
          duration: const Duration(milliseconds: 300),
          curve: Curves.easeOut,
        );
      }
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('无限滚动列表示例')),
      body: ListView.builder(
        controller: _scrollController,
        padding: const EdgeInsets.all(16),
        // 列表长度 = 数据长度 + 1个尾部组件
        itemCount: _dataList.length + 1,
        itemBuilder: (context, index) {
          // 渲染尾部组件
          if (index == _dataList.length) {
            return _buildFooter();
          }
          // 渲染列表项
          return ListTile(
            title: Text(_dataList[index]),
            // 适配生命线对话流的左右布局可在这里自定义item样式
          );
        },
      ),
    );
  }

  // 构建尾部组件
  Widget _buildFooter() {
    if (!_hasMore) {
      return const Padding(
        padding: EdgeInsets.symmetric(vertical: 20),
        child: Center(child: Text('没有更多内容了')),
      );
    }
    if (_isLoading) {
      return const Padding(
        padding: EdgeInsets.symmetric(vertical: 20),
        child: Center(child: CircularProgressIndicator()),
      );
    }
    // 点击加载更多按钮
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 20),
      child: Center(
        child: ElevatedButton(
          onPressed: _loadMoreData,
          child: const Text('加载更多'),
        ),
      ),
    );
  }
}

适配说明

  • 如果需要用GridView实现,仅需把ListView.builder替换为GridView.builder,其余滚动监听、数据源、尾部组件逻辑完全复用即可
  • 类似生命线的对话气泡效果,只需要自定义itemBuilder里的列表项样式,区分左右布局、气泡背景即可
  • 如果使用Riverpod、Bloc等状态管理框架,只需要把数据加载、状态更新的逻辑迁移到对应状态层,视图层的滚动监听逻辑不需要改动

内容的提问来源于stack exchange,提问作者An Tran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:42:16