效果图核心架构上拉使用ScrollController 下拉使用RefreshIndicator核心代码body: RefreshIndicator( onRefresh: _refreshData,//下拉刷新 color: Colors.blue,//指示器箭头颜色 backgroundColor: Colors.white,//指示器背景颜色 displacement: 40.0,//触发下拉距离 child: ListView.builder( controller: _scrollController, itemCount: items.length 1, // 始终显示加载更多组件 itemBuilder: (context, index) { if (index items.length) { return _buildLoadMoreWidget(); } return _buildListItem(items[index]); }, ), ),数据流程图┌─────────────────────────────────────────────────────────────────┐ │ 页面生命周期 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 1️⃣ initState() - 页面初始化 │ │ ├── super.initState() │ │ ├── _loadData() ← 加载第一页数据 │ │ └── _scrollController.addListener() ← 监听滚动 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 2️⃣ build() - 构建UI │ │ ├── Scaffold │ │ ├── AppBar │ │ └── RefreshIndicator │ │ └── ListView.builder │ │ ├── itemCount: items.length 1 │ │ └── itemBuilder: │ │ ├── 最后一项 → _buildLoadMoreWidget() │ │ └── 其他项 → _buildListItem() │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 3️⃣ 等待用户交互 │ │ ├── 下拉刷新 → _refreshData() │ │ ├── 上拉加载 → _loadMoreData() │ │ └── 点击列表项 → onTap() │ └─────────────────────────────────────────────────────────────────┘数据流1.首次进入页面1. DemoPage 构造函数 ↓ 2. createState() → _DemoPageState() ↓ 3. _DemoPageState 构造函数 (初始化变量) • items [] • _page 1 • _isLoadingMore false • _hasMore true ↓ 4. initState() ├── super.initState() ├── _loadData() ← 调用加载方法 └── _scrollController.addListener() ↓ 5. _loadData() 执行 ├── await Future.delayed(1秒) ← 模拟网络请求 ├── 生成20条数据 └── setState() { items newData ← 更新数据 } ↓ 6. build() 执行 (由setState触发) ├── 构建RefreshIndicator └── ListView.builder ├── itemCount 20 1 21 ├── 索引0-19: _buildListItem() └── 索引20: _buildLoadMoreWidget() ↓ 7. 页面显示完成2.上拉加载更多1. 用户滚动到列表底部 ↓ 2. _scrollController.addListener() 触发 ↓ 3. 判断条件: 滚动位置 ≥ 最大滚动位置 - 100 ↓ 4. _loadMoreData() 调用 ├── 检查: _isLoadingMore? _hasMore? ├── _isLoadingMore true ├── setState(() {}) ← 显示加载状态 ├── _page (1→2) ├── await Future.delayed(1秒) ├── 生成新数据 (第2页) ├── setState() { │ items.addAll(newData) ← 追加数据 │ } └── finally: _isLoadingMore false ↓ 5. build() 重新执行 ├── itemCount 40 1 41 ├── 索引0-39: 显示所有数据 └── 索引40: 显示上拉加载更多 (第2次加载后) ↓ 6. 用户再次滚动到底部 (第3页) ↓ 7. _loadMoreData() 再次执行 ├── _page (2→3) ├── 判断 _page 3 → _hasMore false └── setState(() {}) ← 更新状态 ↓ 8. build() 重新执行 ├── itemCount 40 1 41 ├── 索引40: _buildLoadMoreWidget() └── 显示— 已加载全部 — (不再加载)3.下拉刷新1. 用户在列表顶部下拉 ↓ 2. RefreshIndicator 检测到手势 ↓ 3. 下拉距离 ≥ displacement (40.0) ↓ 4. onRefresh: _refreshData() 调用 ├── _page 1 ← 重置页码 ├── _hasMore true ← 重置标志 └── await _loadData(isRefresh: true) ↓ 5. _loadData(isRefresh: true) 执行 ├── await Future.delayed(1秒) ├── 生成20条新数据 (第1页) └── setState() { items newData ← 替换所有数据 } ↓ 6. build() 重新执行 ├── itemCount 20 1 21 └── 显示刷新后的数据 ↓ 7. RefreshIndicator 自动隐藏代码实例import package:flutter/material.dart; class DemoPage extends StatefulWidget { const DemoPage({super.key}); override StateDemoPage createState() _DemoPageState(); } class _DemoPageState extends StateDemoPage { ListString items []; //存储列表数据 int _page 1; //当前页码 bool _isLoadingMore false; //是否正在加载更多 bool _hasMore true; //是否还有更多数据 final int _pageSize 20; //每页数据量 //滚动控制器实现上拉加载 final ScrollController _scrollController ScrollController(); override void initState() { super.initState(); _loadData();//加载第一页数据 //添加滚动监听 _scrollController.addListener(() { //当滚动到距离底部100像素时触发更多 if (_scrollController.position.pixels _scrollController.position.maxScrollExtent - 100) { _loadMoreData(); //加载更多数据 } }); } override void dispose() { _scrollController.dispose(); super.dispose(); } //下拉刷新 Futurevoid _refreshData() async { print( 下拉刷新); _page 1; //重置页码 _hasMore true; //重置标志位 await _loadData(isRefresh: true);//重新加载数据 } //加载数据 Futurevoid _loadData({bool isRefresh false}) async { try { await Future.delayed(Duration(seconds: 1)); //生成模拟数据 ListString newData List.generate( _pageSize, (i) Item ${(_page - 1) * _pageSize i 1} ); //更新UI setState(() { if (isRefresh) { items newData; //刷新替换所有数据 } else { items.addAll(newData); } }); } catch (e) { print(加载数据失败: $e); } } //加载更多数据 Futurevoid _loadMoreData() async { //防止重复加载 if (_isLoadingMore || !_hasMore) return; //设置加载状态 _isLoadingMore true; setState(() {}); // 立即显示加载状态 _page; //页码加1 try { await Future.delayed(Duration(seconds: 1)); // 模拟第3页后没有更多数据 if (_page 3) { _hasMore false; setState(() {}); } else { //生成数据 ListString newData List.generate( _pageSize, (i) Item ${(_page - 1) * _pageSize i 1} ); //添加数据 setState(() { items.addAll(newData); }); } } catch (e) { print(加载更多失败: $e); _page--; } finally { _isLoadingMore false; setState(() {}); } } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: IconButton( onPressed: () Navigator.pop(context), icon: Icon(Icons.arrow_back_ios), ), title: Column( children: [ Text(RefreshIndicator, style: TextStyle(color: Colors.black, fontSize: 18)), Text(上拉加载下拉刷新, style: TextStyle(color: Colors.black.withOpacity(0.7), fontSize: 12)), ], ), centerTitle: true, backgroundColor: Colors.blue, ), body: RefreshIndicator( onRefresh: _refreshData,//下拉刷新 color: Colors.blue,//指示器箭头颜色 backgroundColor: Colors.white,//指示器背景颜色 displacement: 40.0,//触发下拉距离 child: ListView.builder( controller: _scrollController, itemCount: items.length 1, // 始终显示加载更多组件 itemBuilder: (context, index) { if (index items.length) { return _buildLoadMoreWidget(); } return _buildListItem(items[index]); }, ), ), ); } //列表子项 Widget _buildListItem(String text) { return Card( margin: EdgeInsets.symmetric(horizontal: 16, vertical: 6), elevation: 2, child: ListTile( leading: CircleAvatar( backgroundColor: Colors.blue[100], child: Text( text.split( ).last, style: TextStyle(color: Colors.blue[700]), ), ), //标题 title: Text( text, style: TextStyle(fontWeight: FontWeight.w500), ), //副标题 subtitle: Text(这是第${text.split( ).last}项), //尾部按钮 trailing: Icon(Icons.arrow_forward_ios, size: 16, color: Colors.grey), //点击事件 onTap: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(点击了 $text)), ); }, ), ); } // 加载更多组件 Widget _buildLoadMoreWidget() { if (_isLoadingMore) { return Container( padding: EdgeInsets.symmetric(vertical: 20), child: Center( child: Column( children: [ SizedBox( width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.blue, ), ), SizedBox(height: 8), Text( 加载中..., style: TextStyle(color: Colors.grey[600], fontSize: 14), ), ], ), ), ); } else if (!_hasMore) { return Container( padding: EdgeInsets.symmetric(vertical: 20), child: Center( child: Text( — 已加载全部 —, style: TextStyle(color: Colors.grey[400], fontSize: 14), ), ), ); } else { // 显示上拉加载更多提示 return Container( padding: EdgeInsets.symmetric(vertical: 20), child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 上拉加载更多, style: TextStyle(color: Colors.grey[500], fontSize: 13), ), SizedBox(width: 8), Icon( Icons.keyboard_arrow_up, size: 20, color: Colors.grey[500], ), ], ), ), ); } } }