Flutter分页加载列表插件loading_more_list的使用

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

Flutter分页加载列表插件loading_more_list的使用

简介

loading_more_list 是一个支持 ListView, GridView, WaterfallFlowSlivers 的分页加载列表插件。它能帮助开发者更方便地实现列表的懒加载、错误处理和无更多数据提示等功能。

版本与信息

  • pub package
  • GitHub stars
  • GitHub forks
  • GitHub license
  • GitHub issues

Web Demo

使用方法

1. 添加依赖

在项目的 pubspec.yaml 文件中添加 loading_more_list 依赖:

dependencies:
  loading_more_list: any

2. 导入库

在 Dart 文件中导入 loading_more_list 库:

import 'package:loading_more_list/loading_more_list.dart';

3. 准备数据集合

创建一个继承自 LoadingMoreBase 的类来管理数据源:

class TuChongRepository extends LoadingMoreBase<TuChongItem> {
  int pageindex = 1;
  bool _hasMore = true;
  bool forceRefresh = false;

  @override
  bool get hasMore => (_hasMore && length < 30) || forceRefresh;

  @override
  Future<bool> refresh([bool clearBeforeRequest = false]) async {
    _hasMore = true;
    pageindex = 1;
    forceRefresh = !clearBeforeRequest;
    var result = await super.refresh(clearBeforeRequest);
    forceRefresh = false;
    return result;
  }

  @override
  Future<bool> loadData([bool isloadMoreAction = false]) async {
    String url = "";
    if (this.length == 0) {
      url = "https://api.tuchong.com/feed-app";
    } else {
      int lastPostId = this[this.length - 1].postId;
      url =
          "https://api.tuchong.com/feed-app?post_id=$lastPostId&page=$pageindex&type=loadmore";
    }
    bool isSuccess = false;
    try {
      await Future.delayed(Duration(milliseconds: 500));
      var result = await HttpClientHelper.get(url);
      var source = TuChongSource.fromJson(json.decode(result.body));
      if (pageindex == 1) {
        this.clear();
      }
      for (var item in source.feedList) {
        if (item.hasImage && !this.contains(item) && hasMore) this.add(item);
      }
      _hasMore = source.feedList.length != 0;
      pageindex++;
      isSuccess = true;
    } catch (exception, stack) {
      isSuccess = false;
      print(exception);
      print(stack);
    }
    return isSuccess;
  }
}

4. 配置参数

ListConfig 类用于配置 LoadingMoreList 的参数,以下是常用参数:

参数名 描述 默认值
itemBuilder 列表项构建器 必填
sourceList 数据源,必须继承自 LoadingMoreBase 必填
showGlowLeading 是否显示负滚动偏移量的过度滚动光晕 0.0
showGlowTrailing 是否显示正滚动偏移量的过度滚动光晕 -
lastChildLayoutType 最后一项的布局类型 LastChildLayoutType.foot
extendedListDelegate WaterfallFlowExtendedList 的代理 -
gridDelegate GridView 的代理 -
indicatorBuilder 不同加载状态的 widget 构建器 IndicatorWidget
padding 内边距 -
childCountBuilder 子项数量构建器 -

5. 使用示例

ListView 示例

LoadingMoreList(
  ListConfig<TuChongItem>(
    itemBuilder: ItemBuilder.itemBuilder,
    sourceList: listSourceRepository,
    padding: EdgeInsets.all(0.0),
  ),
),

GridView 示例

LoadingMoreList(
  ListConfig<TuChongItem>(
    itemBuilder: ItemBuilder.itemBuilder,
    sourceList: listSourceRepository,
    padding: EdgeInsets.all(0.0),
    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 2,
      crossAxisSpacing: 3.0,
      mainAxisSpacing: 3.0,
    ),
  ),
),

WaterfallFlow 示例

LoadingMoreList(
  ListConfig<TuChongItem>(
    extendedListDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(
      crossAxisCount: 2,
      crossAxisSpacing: 5,
      mainAxisSpacing: 5,
    ),
    itemBuilder: _buildItem,
    sourceList: listSourceRepository,
    padding: EdgeInsets.all(5.0),
  ),
),

CustomScrollView 示例

LoadingMoreCustomScrollView(
  slivers: [
    SliverAppBar(
      pinned: true,
      title: Text("MultipleSliverDemo"),
    ),
    LoadingMoreSliverList(SliverListConfig<TuChongItem>(
      itemBuilder: ItemBuilder.itemBuilder,
      sourceList: listSourceRepository,
    )),
    SliverToBoxAdapter(
      child: Container(
        alignment: Alignment.center,
        child: Text("Next list"),
        color: Colors.blue,
        height: 100.0,
      ),
    ),
    LoadingMoreSliverList(
      SliverListConfig<TuChongItem>(
        itemBuilder: ItemBuilder.itemBuilder,
        sourceList: listSourceRepository1,
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          crossAxisSpacing: 3.0,
          mainAxisSpacing: 3.0,
        ),
      ),
    ),
    SliverPersistentHeader(
      delegate: CommonExtentSliverPersistentHeaderDelegate(
        Container(
          alignment: Alignment.center,
          child: Text("Pinned Content"),
          color: Colors.red,
        ),
        100.0,
      ),
      pinned: true,
    ),
    LoadingMoreSliverList(
      SliverListConfig<TuChongItem>(
        itemBuilder: buildWaterfallFlowItem,
        sourceList: listSourceRepository2,
        padding: EdgeInsets.symmetric(horizontal: 5.0),
        extendedListDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          crossAxisSpacing: 5,
          mainAxisSpacing: 5,
        ),
      ),
    ),
  ],
),

6. 自定义加载指示器

通过 indicatorBuilder 参数可以自定义不同状态下的加载指示器:

enum IndicatorStatus {
  None,
  LoadingMoreBusying,
  FullScreenBusying,
  Error,
  FullScreenError,
  NoMoreLoad,
  Empty
}

Widget _buildIndicator(BuildContext context, IndicatorStatus status) {
  bool isSliver = false;
  Widget widget;

  switch (status) {
    case IndicatorStatus.None:
      widget = Container(height: 0.0);
      break;
    case IndicatorStatus.LoadingMoreBusying:
      widget = Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Container(
            margin: EdgeInsets.only(right: 5.0),
            height: 15.0,
            width: 15.0,
            child: CircularProgressIndicator(),
          ),
          Text("正在加载...不要着急")
        ],
      );
      break;
    // 其他状态...
  }

  return widget;
}

LoadingMoreList(
  ListConfig<TuChongItem>(
    itemBuilder: ItemBuilder.itemBuilder,
    sourceList: listSourceRepository,
    indicatorBuilder: _buildIndicator,
    padding: EdgeInsets.all(0.0),
  ),
),

7. 清理垃圾

通过 collectGarbage 回调可以在合适的时间清理资源(如图片缓存):

LoadingMoreList(
  ListConfig<TuChongItem>(
    extendedListDelegate: ExtendedListDelegate(
      collectGarbage: (List<int> indexes) {
        // 清理垃圾逻辑
      },
    ),
  ),
),

8. 视口构建器

通过 viewportBuilder 可以跟踪进入视口的索引范围:

LoadingMoreList(
  ListConfig<TuChongItem>(
    extendedListDelegate: ExtendedListDelegate(
      viewportBuilder: (int firstIndex, int lastIndex) {
        print('viewport : [$firstIndex,$lastIndex]');
      },
    ),
  ),
),

9. 最后一项布局类型

通过 lastChildLayoutType 可以设置最后一项的特殊布局:

enum LastChildLayoutType {
  none,
  fullCrossAxisExtent,
  foot,
}

LoadingMoreList(
  ListConfig<TuChongItem>(
    lastChildLayoutType: LastChildLayoutType.foot,
  ),
),

10. 接近尾部

通过 closeToTrailing 参数可以让列表内容靠近尾部显示:

LoadingMoreList(
  ListConfig<TuChongItem>(
    extendedListDelegate: ExtendedListDelegate(
      closeToTrailing: true,
    ),
  ),
),

完整示例代码

import 'package:flutter/material.dart';
import 'package:loading_more_list/loading_more_list.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Loading More List Example')),
        body: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TuChongRepository listSourceRepository = TuChongRepository();

  @override
  void initState() {
    super.initState();
    listSourceRepository.initialData();
  }

  @override
  Widget build(BuildContext context) {
    return LoadingMoreList(
      ListConfig<TuChongItem>(
        itemBuilder: (BuildContext context, TuChongItem item, int index) {
          return ListTile(
            title: Text(item.title),
            subtitle: Text(item.content),
          );
        },
        sourceList: listSourceRepository,
        padding: EdgeInsets.all(0.0),
        indicatorBuilder: _buildIndicator,
      ),
    );
  }

  Widget _buildIndicator(BuildContext context, IndicatorStatus status) {
    bool isSliver = false;
    Widget widget;

    switch (status) {
      case IndicatorStatus.None:
        widget = Container(height: 0.0);
        break;
      case IndicatorStatus.LoadingMoreBusying:
        widget = Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              margin: EdgeInsets.only(right: 5.0),
              height: 15.0,
              width: 15.0,
              child: CircularProgressIndicator(),
            ),
            Text("正在加载...不要着急")
          ],
        );
        break;
      case IndicatorStatus.Error:
        widget = GestureDetector(
          onTap: () {
            listSourceRepository.errorRefresh();
          },
          child: Text("好像出现了问题呢?点击重试"),
        );
        break;
      case IndicatorStatus.NoMoreLoad:
        widget = Text("没有更多的了。。不要拖了");
        break;
      default:
        widget = Container();
    }

    return widget;
  }
}

以上是 loading_more_list 插件的详细使用说明和示例代码,希望对您有所帮助!


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

1 回复

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


当然,以下是如何在Flutter项目中使用loading_more_list插件来实现分页加载列表的示例代码。这个插件能够帮助你简化分页加载的实现过程。

首先,确保你的Flutter项目中已经包含了loading_more_list插件。如果还没有添加,可以在pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  loading_more_list: ^x.y.z  # 请将x.y.z替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来是一个完整的示例代码,展示了如何使用loading_more_list插件来实现分页加载列表:

import 'package:flutter/material.dart';
import 'package:loading_more_list/loading_more_list.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Loading More List Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> dataSource = [];
  bool hasMore = true;
  int page = 1;
  int pageSize = 10;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Loading More List Demo'),
      ),
      body: LoadingMoreList<String>(
        onLoadMore: _loadMoreData,
        hasMore: hasMore,
        itemCount: dataSource.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('Item ${dataSource[index]}'),
          );
        },
      ),
    );
  }

  Future<void> _loadMoreData() async {
    // 模拟网络请求
    await Future.delayed(Duration(seconds: 2));

    // 获取新数据
    List<String> newData = [];
    for (int i = 0; i < pageSize && hasMore; i++) {
      int newIndex = (page - 1) * pageSize + i + 1;
      newData.add("Data $newIndex");
      // 假设数据总数是100,超过则没有更多数据
      if (newIndex >= 100) {
        hasMore = false;
      }
    }

    // 更新状态
    setState(() {
      dataSource.addAll(newData);
      page++;
    });
  }
}

代码解释

  1. 依赖添加:在pubspec.yaml中添加loading_more_list插件依赖。

  2. 主应用MyApp是一个简单的Material应用,包含了一个MyHomePage页面。

  3. 状态管理MyHomePage是一个有状态组件,用于管理数据加载的状态。

  4. 数据源和分页逻辑

    • dataSource:存储当前加载的数据。
    • hasMore:指示是否还有更多数据可以加载。
    • pagepageSize:控制分页逻辑。
  5. LoadingMoreList

    • onLoadMore:当需要加载更多数据时调用的函数。
    • hasMore:指示是否还有更多数据。
    • itemCount:当前数据源的长度。
    • itemBuilder:构建每个列表项的Widget。
  6. 数据加载

    • _loadMoreData函数模拟了一个异步的网络请求,延迟2秒后返回新数据。
    • 更新数据源和页码,并使用setState触发UI更新。

这个示例展示了如何使用loading_more_list插件来简化分页加载列表的实现,同时保持了代码的清晰和可维护性。希望这个示例对你有所帮助!

回到顶部