Flutter分页加载工具插件riverpod_paging_utils的使用

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

Flutter分页加载工具插件riverpod_paging_utils的使用

riverpod_paging_utils 是一个为Flutter应用提供分页功能的工具包,基于Riverpod状态管理库。它包括一个通用的 PagingHelperView 小部件和用于基于页面、偏移量和游标的分页逻辑的混入(mixin)。

Demo

Demo Gifs First Error Second Error

特性

  • PagingHelperView: 简化Flutter应用中分页实现的通用小部件。
  • PagePagingNotifierMixin: 用于实现基于页面的分页逻辑的混入。
  • OffsetPagingNotifierMixin: 用于实现基于偏移量的分页逻辑的混入。
  • CursorPagingNotifierMixin: 用于实现基于游标的分页逻辑的混入。

开始使用

安装

pubspec.yaml 文件中添加以下依赖:

dependencies:
  riverpod_paging_utils: ^{latest}

然后运行 flutter pub get 来安装这个包。

使用示例

下面是一个如何使用 PagingHelperView 小部件与 Riverpod 提供者程序(使用 CursorPagingNotifierMixin 混入)的简单例子:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';

// 假设 SampleItem 和 SampleRepository 已经定义
class SampleItem {
  final String id;
  final String name;

  SampleItem({required this.id, required this.name});
}

class SampleRepository {
  Future<(List<SampleItem>, String?)> getByCursor(String? cursor) async {
    // 实现获取数据的逻辑
    return ([], null);
  }
}

@riverpod
class SampleNotifier extends _$SampleNotifier with CursorPagingNotifierMixin<SampleItem> {
  @override
  Future<CursorPagingData<SampleItem>> build() => fetch(cursor: null);

  @override
  Future<CursorPagingData<SampleItem>> fetch({
    required String? cursor,
  }) async {
    final repository = SampleRepository();
    final (items, nextCursor) = await repository.getByCursor(cursor);
    final hasMore = nextCursor != null && nextCursor.isNotEmpty;

    return CursorPagingData(
      items: items,
      hasMore: hasMore,
      nextCursor: nextCursor,
    );
  }
}

final sampleNotifierProvider = SampleNotifier.new;

class SampleScreen extends StatelessWidget {
  const SampleScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sample Screen'),
      ),
      body: PagingHelperView(
        provider: sampleNotifierProvider,
        futureRefreshable: sampleNotifierProvider.future,
        notifierRefreshable: sampleNotifierProvider.notifier,
        contentBuilder: (data, widgetCount, endItemView) => ListView.builder(
          itemCount: widgetCount,
          itemBuilder: (context, index) {
            if (index == widgetCount - 1) {
              return endItemView;
            }

            return ListTile(
              title: Text(data.items[index].name),
              subtitle: Text(data.items[index].id),
            );
          },
        ),
      ),
    );
  }
}

UI自定义

基本自定义

可以使用 ThemeExtension 轻松定制加载和错误状态的外观。例如,如果使用 loading_animation_widget 包,代码设置如下:

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        extensions: [
          PagingHelperViewTheme(
            loadingViewBuilder: (context) => Padding(
              padding: const EdgeInsets.all(16),
              child: Align(
                alignment: Alignment.topCenter,
                child: LoadingAnimationWidget.horizontalRotatingDots(
                  color: Colors.red,
                  size: 100,
                ),
              ),
            ),
            endLoadingViewBuilder: (context) =>
                LoadingAnimationWidget.threeArchedCircle(
              color: Colors.red,
              size: 50,
            ),
          ),
        ],
      ),
      home: const SampleScreen(),
    );
  }
}

高级自定义

如果需要更高级的自定义,比如集成 easy_refresh 包来提供刷新指示器,可以这样修改屏幕代码:

class SampleScreen extends ConsumerWidget {
  const SampleScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Advanced UI Customization'),
      ),
      body: PagingHelperView(
        provider: sampleNotifierProvider,
        futureRefreshable: sampleNotifierProvider.future,
        notifierRefreshable: sampleNotifierProvider.notifier,
        contentBuilder: (data, widgetCount, endItemView) {
          return EasyRefresh(
            onRefresh: () async => ref.refresh(sampleNotifierProvider.future),
            child: ListView.builder(
              itemCount: widgetCount,
              itemBuilder: (context, index) {
                if (index == widgetCount - 1) {
                  return endItemView;
                }

                return ListTile(
                  title: Text(data.items[index].name),
                  subtitle: Text(data.items[index].id),
                );
              },
            ),
          );
        },
      ),
    );
  }
}

以上内容提供了完整的示例demo和详细的说明,帮助您快速上手并使用 riverpod_paging_utils 插件实现分页加载功能。


更多关于Flutter分页加载工具插件riverpod_paging_utils的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter分页加载工具插件riverpod_paging_utils的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,riverpod_paging_utils 是一个用于 Flutter 的分页加载工具插件,它基于 Riverpod 状态管理库。这个插件允许你轻松地实现分页数据加载,适用于需要展示大量数据的应用,比如新闻列表、社交媒体帖子等。

以下是一个使用 riverpod_paging_utils 实现分页加载的简单示例:

  1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加必要的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^1.0.0
  riverpod_paging_utils: ^0.0.1  # 请检查最新版本号
  1. 设置 Riverpod

在你的应用中初始化 Riverpod:

import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}
  1. 定义分页数据源

创建一个分页数据源类,用于获取分页数据。例如,这里我们使用模拟的 API 调用:

import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';

class MyDataSource extends PagingDataSource<int, MyItem> {
  MyDataSource() : super();

  @override
  Future<PageData<int, MyItem>> fetchPage(int pageKey) async {
    // 模拟 API 调用
    List<MyItem> items = List.generate(
      10, // 每页10个项目
      (index) => MyItem(id: pageKey * 10 + index, title: 'Item ${pageKey * 10 + index}'),
    );

    return PageData(
      data: items,
      nextPageKey: pageKey + 1, // 下一页的key
    );
  }
}

class MyItem {
  final int id;
  final String title;

  MyItem({required this.id, required this.title});
}
  1. 创建分页控制器

使用 PagingController 管理分页逻辑:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';

final myPagingControllerProvider = StateNotifierProvider<PagingController<int, MyItem>, PagingState<int, MyItem>>(
  (ref) {
    return PagingController<int, MyItem>(
      firstPageKey: 0,
      dataSource: MyDataSource(),
    );
  },
);
  1. 在 UI 中使用分页数据

在你的 Flutter 组件中使用分页数据:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';

class MyApp extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final pagingController = ref.watch(myPagingControllerProvider);

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Paging Example')),
        body: RefreshIndicator(
          onRefresh: () async {
            await pagingController.refresh();
          },
          child: PagingListView<int, MyItem>(
            pagingController: pagingController,
            builderDelegate: PagingLoadMoreBuilderDelegate<MyItem>(
              itemBuilder: (context, item, index) {
                return ListTile(title: Text(item.title));
              },
              loadingBuilder: (context) {
                return Center(child: CircularProgressIndicator());
              },
              errorBuilder: (context, error, stackTrace) {
                return Center(child: Text('Error: $error'));
              },
              noMoreItemsBuilder: (context) {
                return Center(child: Text('No more items'));
              },
            ),
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们:

  • 创建了一个分页数据源 MyDataSource,它模拟了一个 API 调用并返回分页数据。
  • 使用 PagingController 管理分页状态和数据源。
  • 在 UI 中使用 PagingListView 显示分页数据,并处理加载、错误和无更多项目的场景。

这样,你就可以在 Flutter 应用中实现分页加载功能了。确保根据你的实际需求调整数据源和 UI 组件。

回到顶部