Flutter无限滚动列表插件bloc_infinite_list的使用
Flutter无限滚动列表插件bloc_infinite_list的使用
Motivation
作为flutter_bloc
用户,您可能有过为列表构建而烦恼的经历。许多应用程序都有无限滚动列表的功能,尽管每个应用的具体业务需求不同,但它们的无限列表功能都基于以下三个主要点:
- 拥有一个列表
- 从列表中查询项目
- 修改列表中的项目
然而,我们通常都是从头开始手动构建这些功能,这不仅耗时而且容易引入错误。为了应对这些问题,bloc_infinite_list
提供了多种特性来简化无限列表的创建。
告诉您的项目经理,实现滚动功能需要大量时间,而您可以借此机会喝杯咖啡享受一下😎。
Examples
本仓库包含了一个基本示例应用,可以在example文件夹中找到。
Installation
在pubspec.yaml
文件中添加依赖:
dependencies:
bloc_infinite_list: ^1.0.0
Usage
这个包提供了一些Bloc和Cubit来帮助你更轻松地构建无限列表:
- Cubit
- DefaultInfiniteListCubit
- InfiniteListCubit
- MultiInfiniteListCubit
- Bloc
- DefaultInfiniteListBloc
- InfiniteListBloc
Comfortable Methods
你可以使用以下便捷方法(仅限于Cubit),如果你尝试在Bloc中使用这些方法,将会收到断言错误。对于Bloc,你应该使用bloc.triggerXXX()
方法。
cubit.fetchNext(); // 获取下一页
cubit.reinitialize(); // 重新初始化列表,适用于下拉刷新
cubit.reset(); // 清空当前列表
cubit.addItem(T item); // 添加单个元素到列表末尾
cubit.addItems(List<T> items); // 添加多个元素到列表末尾
cubit.insert(int idx, T item); // 在指定索引处插入元素
cubit.remove(T item); // 移除特定元素
cubit.removeAt(int idx); // 移除指定索引处的元素
cubit.replace(T before, T after); // 替换单个元素
cubit.replaceAt(int idx, T item); // 替换指定索引处的元素
cubit.replaceWhere(bool Function(T) test, T Function(T element) willReplacedItemGenerator); // 根据条件替换元素
Cubit
DefaultInfiniteListCubit
class PlayerCubit extends DefaultInfiniteListCubit<Player> {
PlayerCubit(PlayerRepository playerRepository)
: super(
fetch: (page, size, state, cancelToken) =>
playerRepository.getAll(page: page, size: size, cancelToken: cancelToken),
initialState: DefaultInfiniteListState(infList: InfiniteList()),
);
}
Custom State
class PlayerState extends InfiniteListState<Player, PlayerState> {
final int id;
PlayerState({
super.infList,
required this.id,
});
...
}
class PlayerCubit extends InfiniteListCubit<Player, PlayerState> {
PlayerCubit(PlayerRepository playerRepository)
: super(
fetch: (page, size, state, cancelToken) =>
playerRepository.getAll(page: page, size: size, cancelToken: cancelToken),
initialState: DefaultInfiniteListState(infList: InfiniteList()),
);
}
InfiniteListBloc
InfiniteListBloc
内置了一些事件,默认情况下无需注册事件处理器即可使用。这些事件等同于InfiniteListCubit
中的便捷方法。
Default Event & State
class FoodBloc extends DefaultInfiniteListBloc<Food> {
...same as cubit
}
Custom Event & State
abstract class FoodEvent extends InfiniteListEvent<Food> {
const FoodEvent();
}
abstract class FoodEventHadForLaunch extends InfiniteListEvent<Food> {
const FoodEventHadForLaunch();
}
---
class FoodBloc extends InfiniteListBloc<Food, FoodEvent, FoodState> {
FoodBloc(){
on<FoodEventHadForLaunch>(_onHadForLaunch);
}
_onHadForLaunch(event, emit);
}
add(InfiniteListEvent.fetchNext());
add(FoodEventHadForLaunch());
示例代码
以下是一个完整的示例代码,展示了如何使用bloc_infinite_list
创建一个简单的无限滚动列表应用。
import 'package:flutter/material.dart';
import 'package:bloc_infinite_list/bloc_infinite_list.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: AlarmPage(),
);
}
}
class AlarmPage extends StatelessWidget {
const AlarmPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Infinite List Example')),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: const [
Tile(
exampleName: 'Default Infinite Cubit',
page: DefaultInfiniteCubitAlarmPage(),
),
Tile(
exampleName: 'Infinite Cubit',
page: InfiniteCubitAlarmPage(),
),
Tile(
exampleName: 'Default Infinite Bloc',
page: DefaultInfiniteBlocAlarmPage(),
),
Tile(
exampleName: 'Infinite Bloc',
page: InfiniteBlocAlarmPage(),
),
],
),
),
);
}
}
class Tile extends StatelessWidget {
final String exampleName;
final Widget page;
const Tile({super.key, required this.exampleName, required this.page});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => page,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
exampleName,
style: const TextStyle(fontSize: 26),
),
),
);
}
}
// 示例页面:DefaultInfiniteCubitAlarmPage
class DefaultInfiniteCubitAlarmPage extends StatelessWidget {
const DefaultInfiniteCubitAlarmPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Default Infinite Cubit Alarm Page')),
body: ListView.builder(
itemCount: 50, // 示例数据量
itemBuilder: (context, index) {
return ListTile(title: Text('Item $index'));
},
),
);
}
}
// 其他页面类似...
请注意,上述示例代码中的DefaultInfiniteCubitAlarmPage
、InfiniteCubitAlarmPage
、DefaultInfiniteBlocAlarmPage
和InfiniteBlocAlarmPage
应根据实际需求进行具体实现。
更多关于Flutter无限滚动列表插件bloc_infinite_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter无限滚动列表插件bloc_infinite_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个使用 bloc_infinite_list
插件在 Flutter 中实现无限滚动列表的示例代码。这个示例展示了如何使用 bloc_infinite_list
来处理分页数据加载。
首先,确保在 pubspec.yaml
文件中添加 bloc_infinite_list
依赖:
dependencies:
flutter:
sdk: flutter
bloc: ^8.0.0
flutter_bloc: ^8.0.0
bloc_infinite_list: ^0.2.0 # 请检查最新版本号
然后,运行 flutter pub get
以获取依赖项。
接下来,我们创建一个 Flutter 应用,使用 bloc_infinite_list
来实现无限滚动列表。
1. 创建数据模型
class Item {
final int id;
final String text;
Item({required this.id, required this.text});
}
2. 创建 BLoC 和事件/状态
2.1 定义事件
import 'package:equatable/equatable.dart';
abstract class InfiniteListEvent extends Equatable {
const InfiniteListEvent();
@override
List<Object?> get props => [];
}
class LoadMoreEvent extends InfiniteListEvent {}
2.2 定义状态
import 'package:bloc_infinite_list/bloc_infinite_list.dart';
import 'package:meta/meta.dart';
class InfiniteListState extends Equatable {
final List<Item> items;
final bool hasReachedMax;
final InfiniteListStatus status;
const InfiniteListState({
required this.items,
required this.hasReachedMax,
this.status = InfiniteListStatus.idle,
});
@override
List<Object?> get props => [items, hasReachedMax, status];
}
2.3 创建 BLoC
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:bloc_infinite_list/bloc_infinite_list.dart';
class InfiniteListBloc extends Bloc<InfiniteListEvent, InfiniteListState> {
InfiniteListBloc() : super(InfiniteListState(items: [], hasReachedMax: false));
final List<Item> _dummyData = List.generate(
100,
(index) => Item(id: index, text: 'Item $index'),
);
int _currentPage = 1;
@override
Stream<InfiniteListState> mapEventToState(
InfiniteListEvent event,
) async* {
if (event is LoadMoreEvent) {
if (_currentPage * 10 >= _dummyData.length) {
yield state.copyWith(hasReachedMax: true);
} else {
yield state.copyWith(
status: InfiniteListStatus.loading,
);
await Future.delayed(const Duration(seconds: 1)); // Simulate API call
final List<Item> newItems = _dummyData.skip((_currentPage - 1) * 10).take(10).toList();
yield state.copyWith(
items: List.from(state.items)..addAll(newItems),
hasReachedMax: _currentPage * 10 >= _dummyData.length,
status: InfiniteListStatus.idle,
);
_currentPage++;
}
}
}
}
3. 创建 UI
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:bloc_infinite_list/bloc_infinite_list.dart';
import 'infinite_list_bloc.dart'; // 假设你把 BLoC 文件命名为 infinite_list_bloc.dart
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Infinite Scroll List')),
body: BlocProvider(
create: (context) => InfiniteListBloc(),
child: InfiniteList<Item>(
bloc: context.read<InfiniteListBloc>(),
itemBuilder: (context, item) {
return ListTile(
title: Text(item.text),
);
},
loadingWidget: Center(child: CircularProgressIndicator()),
hasReachedMax: (state) => state.hasReachedMax,
onLoadMore: (context, state) {
context.read<InfiniteListBloc>().add(LoadMoreEvent());
},
initialState: context.read<InfiniteListBloc>().state,
),
),
),
);
}
}
这个示例展示了如何使用 bloc_infinite_list
插件来创建一个简单的无限滚动列表。InfiniteList
小部件负责监听 BLoC 的状态,并在用户滚动到底部时触发加载更多事件。BLoC 负责处理数据加载逻辑,并在数据加载完成时更新状态。