Flutter无限滚动列表插件bloc_infinite_list的使用

发布于 1周前 作者 h691938207 来自 Flutter

Flutter无限滚动列表插件bloc_infinite_list的使用

Motivation

作为flutter_bloc用户,您可能有过为列表构建而烦恼的经历。许多应用程序都有无限滚动列表的功能,尽管每个应用的具体业务需求不同,但它们的无限列表功能都基于以下三个主要点:

  1. 拥有一个列表
  2. 从列表中查询项目
  3. 修改列表中的项目

然而,我们通常都是从头开始手动构建这些功能,这不仅耗时而且容易引入错误。为了应对这些问题,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'));
        },
      ),
    );
  }
}

// 其他页面类似...

请注意,上述示例代码中的DefaultInfiniteCubitAlarmPageInfiniteCubitAlarmPageDefaultInfiniteBlocAlarmPageInfiniteBlocAlarmPage应根据实际需求进行具体实现。


更多关于Flutter无限滚动列表插件bloc_infinite_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于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 负责处理数据加载逻辑,并在数据加载完成时更新状态。

回到顶部