BaseListPage 架构
BaseListPage 是专门用于处理列表页面的基类,继承自 BasePage。它封装了分页加载、下拉刷新、触底加载更多等复杂的列表逻辑,让开发者只需关注 Item 的渲染。
核心功能
- 自动分页: 内置分页逻辑,自动管理页码。
- 下拉刷新: 集成 RefreshIndicator(可自定义)。
- 触底加载: 滚动到底部自动触发加载下一页。
- 状态管理: 自动处理首次加载、刷新中、加载更多中、无更多数据、加载失败等状态。
快速上手
1. 定义 ViewModel
继承 BaseListViewModel<T>,其中 T 是列表项的数据模型。
dart
class UserListViewModel extends BaseListViewModel<User> {
@override
Future<List<User>> loadData({required int pageNum}) async {
// 调用 API 获取数据
// 无需处理分页状态,基类会自动处理
return await UserRepository.getUsers(page: pageNum);
}
}2. 定义 Page
继承 BaseListPage<T, VM>,实现 buildItem 方法。
dart
class UserListPage extends BaseListPage<User, UserListViewModel> {
const UserListPage({super.key});
@override
State<UserListPage> createState() => _UserListPageState();
}
class _UserListPageState extends BaseListPageState<User, UserListViewModel, UserListPage> {
@override
UserListViewModel createViewModel() => UserListViewModel();
@override
String get title => '用户列表';
// 开启下拉刷新
@override
bool get enableRefresh => true;
// 渲染单个列表项
@override
Widget buildItem(BuildContext context, User item, int index) {
return ListTile(
leading: CircleAvatar(backgroundImage: NetworkImage(item.avatar)),
title: Text(item.name),
subtitle: Text(item.email),
);
}
}进阶配置
自定义列表容器
默认使用 ListView.builder,你可以重写 buildListWidget 来使用 GridView 或其他容器。
dart
@override
Widget? buildListWidget(BuildContext context) {
return GridView.builder(
controller: _controller, // 必须使用基类的 controller
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: viewModel.items.length,
itemBuilder: (context, index) {
return buildItem(context, viewModel.items[index], index);
},
);
}添加 Header 和 Footer
dart
@override
Widget? buildHeader(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
child: const Text('这是列表头部'),
);
}
@override
Widget? buildFooter(BuildContext context) {
// 注意:这是列表内容的底部,不是加载更多的 Footer
return const Padding(
padding: EdgeInsets.all(16),
child: Text('这是列表底部'),
);
}自定义加载更多指示器
你可以重写 loadMoreFooterBuilder 来自定义加载更多的样式,或者使用全局主题配置。
dart
@override
Widget? loadMoreFooterBuilder(BuildContext context, bool hasMore, bool isLoadingMore) {
if (!hasMore) {
return const Center(child: Text('到底啦~'));
}
if (isLoadingMore) {
return const Center(child: CircularProgressIndicator());
}
return null;
}常见问题
1. 如何手动刷新列表?
在 ViewModel 中调用 refresh() 方法:
dart
// 在 Page 中
viewModel.refresh();
// 或者带参数(静默刷新)
viewModel.refresh(init: false);2. 如何修改分页参数?
可以在 ViewModel 中重写分页配置:
dart
@override
int get pageSize => 20; // 默认 10
@override
int get firstPageNum => 0; // 默认 13. 如何处理搜索?
搜索本质上是带参数的刷新。
dart
class UserListViewModel extends BaseListViewModel<User> {
String _keyword = '';
void search(String keyword) {
_keyword = keyword;
refresh(); // 触发刷新,重新调用 loadData
}
@override
Future<List<User>> loadData({required int pageNum}) async {
return await UserRepository.getUsers(page: pageNum, keyword: _keyword);
}
}