Flutter分页加载插件bloc_pagination的使用
Flutter分页加载插件bloc_pagination的使用
在本文中,我们将详细介绍如何使用bloc_pagination
插件来实现Flutter应用中的分页加载功能。此插件通过BLoC模式(Business Logic Component)帮助开发者更方便地处理分页逻辑。
安装
首先,在你的pubspec.yaml
文件中添加依赖:
dependencies:
bloc_pagination: // 添加最新版本
然后导入该包:
import 'package:bloc_pagination/bloc_pagination.dart';
基本用法
以下是一个基本的使用示例:
class MyBloc extends PaginationBloc {
[@override](/user/override)
Future<ListResponse<PaginationModel>> findAll(int page,
{AbstractQueryParameters? queryParameters}) async {
/// 你的数据源
return readRepository.findAll(page, params: queryParameters);
}
}
class MyWidget extends StatelessWidget {
final MyBloc _bloc = MyBloc();
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: BlocPagination<TempModel, ErrorWrapper>(
bloc: _bloc,
blocListener: (context, state) {},
firstPageErrorBuilder: (context, error) {
return Center(
child: Text(error.message.toString()),
);
},
bannerPinned: true,
banner: SliverAppBarDelegate(
maxHeight: 100,
minHeight: 100,
child: Container(
color: Colors.green,
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text('header widget'),
),
),
footerPinned: true,
footer: Container(
color: Colors.green,
height: 100,
width: double.infinity,
child: Text('footer widget'),
),
itemsBuilder: (context, item, index) => InkWell(
onTap: () => _bloc.add(EditListTypePaginationEvent(
listType: _bloc.state.listType.isListed
? ListType.gridView
: ListType.listView)),
child: Container(
color: Colors.green,
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
height: 200,
child: Text('index ${item.id}'),
),
),
),
);
}
}
示例代码
以下是完整的示例代码:
import 'package:bloc_pagination/bloc_pagination.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _bloc = MyBloc();
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Pagination page'),
),
body: BlocPagination<TempModel, ErrorWrapper>(
bloc: _bloc,
firstPageErrorBuilder: (context, error) {
return Center(
child: Text(error.message.toString()),
);
},
bannerPinned: true,
banner: SliverAppBarDelegate(
maxHeight: 100,
minHeight: 100,
child: Container(
color: Colors.greenAccent,
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text('header'),
),
),
footerPinned: true,
footer: Container(
color: Colors.greenAccent,
height: 100,
width: MediaQuery.of(context).size.width,
child: Text('footer'),
),
itemsBuilder: (context, item, index) => InkWell(
onTap: () => _bloc.add(EditListTypePaginationEvent(
listType: _bloc.state.listType.isListed
? ListType.gridView
: ListType.listView)),
child: Container(
color: Colors.green,
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
height: 200,
child: Text('index ${item.id}'),
),
),
));
}
}
class MyBloc extends PaginationBloc<TempModel> {
MyBloc() : super(initialType: ListType.listView);
[@override](/user/override)
Future<ListResponse<TempModel>> findAll(int page,
{AbstractQueryParameters? queryParameters}) async {
await Future.delayed(const Duration(seconds: 1));
// 抛出异常作为 ErrorWrapper() 或其他异常
// throw ErrorWrapper(message: 'error');
return ListedData(
data: [for (int i = 0; i < 10; i++) TempModel(i)], total: 20);
}
}
class TempModel {
final int id;
TempModel(this.id);
}
class ListedData with ListResponse<TempModel> {
[@override](/user/override)
List<TempModel> data;
[@override](/user/override)
int? total;
ListedData({required this.data, this.total});
}
class ErrorWrapper {
String? message;
int? statusCode;
ErrorWrapper({this.message, this.statusCode});
}
更多关于Flutter分页加载插件bloc_pagination的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复
更多关于Flutter分页加载插件bloc_pagination的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter中使用bloc_pagination
插件实现分页加载的示例代码。bloc_pagination
是一个非常流行的Flutter包,用于处理分页数据的加载和状态管理。
首先,确保你已经在pubspec.yaml
文件中添加了bloc
和bloc_pagination
的依赖:
dependencies:
flutter:
sdk: flutter
flutter_bloc: ^8.0.0 # 确保版本是最新的
bloc_pagination: ^0.2.0 # 确保版本是最新的
然后运行flutter pub get
来获取这些依赖。
接下来,让我们编写一个简单的分页加载示例。假设我们有一个API返回分页的用户列表。
1. 创建用户模型
class User {
final String id;
final String name;
User({required this.id, required this.name});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as String,
name: json['name'] as String,
);
}
}
2. 创建用户事件、状态和Bloc
用户事件
import 'package:equatable/equatable.dart';
abstract class UserEvent extends Equatable {
const UserEvent();
}
class LoadUsersEvent extends UserEvent {
final int page;
const LoadUsersEvent({required this.page});
@override
List<Object?> get props => [page];
}
用户状态
import 'package:bloc_pagination/bloc_pagination.dart';
import 'package:meta/meta.dart';
class UserState extends PaginatedState<User> {
UserState({
required List<User> items,
required PaginationController<User> paginationController,
}) : super(items: items, paginationController: paginationController);
@override
List<Object?> get props => [items, paginationController];
}
用户Bloc
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:bloc_pagination/bloc_pagination.dart';
import 'package:meta/meta.dart';
class UserBloc extends Bloc<UserEvent, UserState> with PaginationMixin<User> {
UserBloc({required PaginationRepository<User> repository})
: super(UserState(
items: [],
paginationController: PaginationController(
initialPage: 1,
pageOptions: PageOptions(limit: 10),
),
)) {
on<LoadUsersEvent>((event, emitter) async {
await fetchPage(
event.page,
emitter,
repository: repository,
);
});
}
@override
Future<void> fetchPage(
int page,
Emitter<UserState> emitter, {
required PaginationRepository<User> repository,
}) async {
try {
final List<User> newItems = await repository.fetchPage(
page: page,
params: {}, // 可以在这里传递额外的查询参数
);
final List<User> items = [...state.items, ...newItems];
emitter.emit(
state.copyWith(
items: items,
paginationController: state.paginationController.copyWith(
page: page,
itemCount: items.length,
),
),
);
} catch (_) {
// 处理错误
}
}
}
3. 创建分页存储库
import 'dart:convert';
import 'package:bloc_pagination/bloc_pagination.dart';
import 'package:http/http.dart' as http;
class UserRepository implements PaginationRepository<User> {
@override
Future<List<User>> fetchPage(
int page, {
Map<String, dynamic>? params,
}) async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/users'),
// 注意:这里的API不支持分页,这里只是示例,实际项目中需要传递分页参数
);
final List<dynamic> body = jsonDecode(response.body);
// 模拟分页,只返回前page*limit个用户
return body
.map((dynamic item) => User.fromJson(item as Map<String, dynamic>))
.take(page * 10)
.skip((page - 1) * 10)
.toList();
}
}
4. 使用BlocProvider和PaginationView
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:bloc_pagination/bloc_pagination.dart';
import 'user_bloc.dart';
import 'user_repository.dart';
void main() {
runApp(
BlocProvider<UserBloc>(
create: (context) => UserBloc(repository: UserRepository()),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('User List')),
body: BlocConsumer<UserBloc, UserState>(
listener: (context, state) {},
builder: (context, state) {
return PaginationView<User>(
paginationController: state.paginationController,
builderDelegate: PaginationViewBuilderDelegate<User>(
itemBuilder: (context, user, index) {
return ListTile(title: Text(user.name));
},
emptyBuilder: (context) {
return Center(child: Text('No users found'));
},
errorBuilder: (context, error) {
return Center(child: Text('Error: $error'));
},
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<UserBloc>().add(LoadUsersEvent(page: state.paginationController.page + 1));
},
tooltip: 'Load More',
child: Icon(Icons.add),
),
),
);
}
}
注意事项
- 上述示例中,API调用并没有真正分页,因为示例API不支持分页。在实际项目中,你需要根据API文档传递分页参数(如
page
和limit
)。 - 错误处理和加载状态管理在实际项目中需要更详细的处理。
- 示例中的
PaginationView
和PaginationViewBuilderDelegate
是bloc_pagination
包提供的便捷组件,用于处理分页视图的构建。
希望这个示例代码对你有所帮助!