Flutter快速加载更多列表插件loading_more_list_fast的使用

Flutter快速加载更多列表插件loading_more_list_fast的使用

loading_more_list_fast 是一个支持 ListView, GridView, WaterfallFlowSlivers 的加载更多列表插件。它可以帮助开发者轻松实现具有加载更多功能的列表。

使用

添加依赖

pubspec.yaml 文件中添加依赖:

dependencies:
  loading_more_list: any

然后在 Dart 文件中导入库:

import 'package:loading_more_list/loading_more_list_fast.dart';

准备数据集合

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

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;
  }
}

参数

ListConfig 类定义了加载更多列表的主要参数:

参数名 描述 默认值
itemBuilder 列表项构建器 必填
sourceList 数据源列表,必须扩展 LoadingMoreBase 类型 必填
showGlowLeading 是否显示负滚动偏移方向的溢出光晕 0.0
showGlowTrailing 是否显示正滚动偏移方向的溢出光晕 -
lastChildLayoutType 最后一个子项的布局类型(加载更多/无更多项目) LastChildLayoutType.foot
extendedListDelegate WaterfallFlowExtendedList 的委托 -
gridDelegate GridView 的委托 -
indicatorBuilder 不同加载状态的指示器构建器 IndicatorWidget
padding 插入子级 Sliver 的空间量(仅适用于 SliverListConfig -
childCountBuilder 获取子项计数的构建器,输入为 sourceList.length -

组件

LoadingMoreList

用于创建基本的加载更多列表:

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

GridView

通过 gridDelegate 参数定义 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

通过 extendedListDelegate 参数定义 WaterfallFlow

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

Sliver/CustomScrollView

以下代码展示了如何在 CustomScrollView 中构建加载更多列表:

LoadingMoreCustomScrollView(
  slivers: <Widget>[
    SliverAppBar(
      pinned: true,
      title: Text("MultipleSliverDemo"),
    ),
    /// SliverList
    LoadingMoreSliverList(SliverListConfig<TuChongItem>(
      itemBuilder: ItemBuilder.itemBuilder,
      sourceList: listSourceRepository,
    )),
    SliverToBoxAdapter(
      child: Container(
        alignment: Alignment.center,
        child: Text("Next list"),
        color: Colors.blue,
        height: 100.0,
      ),
    ),
    /// SliverGrid
    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,
    ),
    /// SliverWaterfallFlow
    LoadingMoreSliverList(
      SliverListConfig<TuChongItem>(
        itemBuilder: buildWaterfallFlowItem,
        sourceList: listSourceRepository2,
        padding: EdgeInsets.symmetric(horizontal: 5.0),
        extendedListDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          crossAxisSpacing: 5,
          mainAxisSpacing: 5,
        ),
      ),
    ),
  ],
)

指示器状态

定义加载状态,使用 indicatorBuilder 参数:

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

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

// 可以使用 IndicatorWidget 或自行构建 Widget
// 在此示例中,我们定义所有状态。
Widget _buildIndicator(BuildContext context, IndicatorStatus status) {
  // 如果您的列表是 Sliver 列表,则应为其构建 Sliver 指示器
  // isSliver = true,当在 Sliver 列表中使用时
  bool isSliver = false;

  Widget widget;
  switch (status) {
    case IndicatorStatus.None:
      widget = Container(height: 0.0);
      break;
    case IndicatorStatus.LoadingMoreBusying:
      widget = Row(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Container(
            margin: EdgeInsets.only(right: 5.0),
            height: 15.0,
            width: 15.0,
            child: getIndicator(context),
          ),
          Text("正在加载...不要着急")
        ],
      );
      widget = _setbackground(false, widget, 35.0);
      break;
    case IndicatorStatus.FullScreenBusying:
      widget = Row(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Container(
            margin: EdgeInsets.only(right: 0.0),
            height: 30.0,
            width: 30.0,
            child: getIndicator(context),
          ),
          Text("正在加载...不要着急")
        ],
      );
      widget = _setbackground(true, widget, double.infinity);
      if (isSliver) {
        widget = SliverFillRemaining(
          child: widget,
        );
      } else {
        widget = CustomScrollView(
          slivers: <Widget>[
            SliverFillRemaining(
              child: widget,
            )
          ],
        );
      }
      break;
    case IndicatorStatus.Error:
      widget = Text(
        "好像出现了问题呢?",
      );
      widget = _setbackground(false, widget, 35.0);

      widget = GestureDetector(
        onTap: () {
          listSourceRepository.errorRefresh();
        },
        child: widget,
      );

      break;
    case IndicatorStatus.FullScreenError:
      widget = Text(
        "好像出现了问题呢?",
      );
      widget = _setbackground(true, widget, double.infinity);
      widget = GestureDetector(
        onTap: () {
          listSourceRepository.errorRefresh();
        },
        child: widget,
      );
      if (isSliver) {
        widget = SliverFillRemaining(
          child: widget,
        );
      } else {
        widget = CustomScrollView(
          slivers: <Widget>[
            SliverFillRemaining(
              child: widget,
            )
          ],
        );
      }
      break;
    case IndicatorStatus.NoMoreLoad:
      widget = Text("没有更多的了。。不要拖了");
      widget = _setbackground(false, widget, 35.0);
      break;
    case IndicatorStatus.Empty:
      widget = EmptyWidget(
        "这里是空气!",
      );
      widget = _setbackground(true, widget, double.infinity);
      if (isSliver) {
        widget = SliverToBoxAdapter(
          child: widget,
        );
      } else {
        widget = CustomScrollView(
          slivers: <Widget>[
            SliverFillRemaining(
              child: widget,
            )
          ],
        );
      }
      break;
  }
  return widget;
}

收集垃圾

跟踪将要收集的索引,可以在那一刻收集垃圾(例如图像缓存):

LoadingMoreList(
  ListConfig<TuChongItem>(
    extendedListDelegate: ExtendedListDelegate(
      collectGarbage: (List<int> indexes) {
        /// 收集垃圾
      },
    ),
  ),
)

视口构建器

跟踪进入视口的索引,这不包括缓存范围:

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

最后子项布局类型

在最后一个子项为加载更多/无更多项目的情况下,构建最后一个子项作为特殊子项:

enum LastChildLayoutType {
  /// 作为默认子项
  none,

  /// 跟随最大子项的尾部布局偏移,并使用完整的交叉轴扩展
  /// 在 `[ExtendedGridView]` 和 `[WaterfallFlow]` 中,最后一个子项作为加载更多项目/无更多项目
  /// 具有完整的交叉轴扩展
  fullCrossAxisExtent,

  /// 在尾部作为脚部并使用完整的交叉轴扩展
  /// 当子项不满视口时显示无更多项目
  /// 如果子项满视口,则与 `fullCrossAxisExtent` 相同
  foot,
}

关闭到尾部

Listreverse 属性为 true 时,布局如下: 类似于聊天列表,新会话将插入到零索引处。但当项目不满视口时,这并不正确。

为了解决这个问题,您可以将 closeToTrailing 设置为 true,布局如下: 支持 [ExtendedGridView], [ExtendedList], [WaterfallFlow]。 并且即使 reversefalse 时,布局也会靠近尾部。

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

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

1 回复

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


loading_more_list_fast 是一个用于 Flutter 的插件,可以帮助你快速实现加载更多列表的功能。它支持懒加载、下拉刷新、上拉加载更多等常用功能,并且性能优化较好。以下是使用 loading_more_list_fast 的基本步骤和示例代码。

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 loading_more_list_fast 依赖:

dependencies:
  flutter:
    sdk: flutter
  loading_more_list_fast: ^2.0.0

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

2. 基本使用

以下是一个简单的示例,展示如何使用 loading_more_list_fast 实现一个加载更多列表。

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

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

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

class LoadingMoreListDemo extends StatefulWidget {
  [@override](/user/override)
  _LoadingMoreListDemoState createState() => _LoadingMoreListDemoState();
}

class _LoadingMoreListDemoState extends State<LoadingMoreListDemo> {
  // 模拟数据源
  final List<int> _dataSource = List.generate(20, (index) => index);

  // 加载更多数据
  Future<bool> _loadMore() async {
    await Future.delayed(Duration(seconds: 2)); // 模拟网络请求延迟
    setState(() {
      _dataSource.addAll(List.generate(10, (index) => _dataSource.length + index));
    });
    return true;
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Loading More List Demo'),
      ),
      body: LoadingMoreList<int>(
        itemBuilder: (BuildContext context, int item, int index) {
          return ListTile(
            title: Text('Item $item'),
          );
        },
        sourceList: _dataSource,
        loadMore: _loadMore,
        hasMore: true, // 是否还有更多数据
        onLoadMore: () async {
          await _loadMore();
        },
        onRefresh: () async {
          // 模拟刷新数据
          await Future.delayed(Duration(seconds: 2));
          setState(() {
            _dataSource.clear();
            _dataSource.addAll(List.generate(20, (index) => index));
          });
          return true;
        },
      ),
    );
  }
}
回到顶部