自学内容网 自学内容网

Flutter下拉刷新上拉加载的简单实现方式二

 一个简单的Flutter应用程序,展示了如何实现下拉刷新和上拉加载更多的功能。

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

class MyRefreshDemoPage extends StatefulWidget {
  const MyRefreshDemoPage({super.key});

  @override
  MyRefreshDemoPageState createState() => MyRefreshDemoPageState();
}

class MyRefreshDemoPageState extends State<MyRefreshDemoPage> {
  final int pageSize = 30;

  bool disposed = false;

  List<String> dataList = [];

  final ScrollController _scrollController = ScrollController();

  Future<void> onRefresh() async {
    await Future.delayed(const Duration(seconds: 2));
    dataList.clear();
    for (int i = 0; i < pageSize; i++) {
      dataList.add("refresh");
    }
    if (disposed) {
      return;
    }
    setState(() {});
  }

  Future<void> loadMore() async {
    await Future.delayed(const Duration(seconds: 2));
    for (int i = 0; i < pageSize; i++) {
      dataList.add("loadmore");
    }
    if (disposed) {
      return;
    }
    setState(() {});
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    Future.delayed(const Duration(milliseconds: 500), () {
      _scrollController.animateTo(-150,
          duration: const Duration(milliseconds: 600), curve: Curves.linear);
      return true;
    });
  }

  @override
  void dispose() {
    disposed = true;
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("MyRefreshDemoPage"),
      ),
      body: NotificationListener(
        onNotification: (ScrollNotification notification) {
          //判断是否满足触发加载更多的条件
          if (notification is ScrollEndNotification) {
            if (_scrollController.position.pixels > 0 &&
                _scrollController.position.pixels ==
                    _scrollController.position.maxScrollExtent) {
              loadMore();
            }
          }
          return false;
        },
        child: CustomScrollView(
          controller: _scrollController,

          //回弹效果
          physics: const BouncingScrollPhysics(
              parent: AlwaysScrollableScrollPhysics()),
          slivers: <Widget>[
            //控制显示刷新的CupertinoSliverRefreshControl
            CupertinoSliverRefreshControl(
              refreshIndicatorExtent: 100,
              refreshTriggerPullDistance: 140,
              onRefresh: onRefresh,
            ),
            SliverSafeArea(
              sliver: SliverList(
                //代理显示
                delegate: SliverChildBuilderDelegate(
                  (BuildContext context, int index) {
                    if (index == dataList.length) {
                      return Container(
                        margin: const EdgeInsets.all(10),
                        child: const Align(
                          child: CircularProgressIndicator(),
                        ),
                      );
                    }
                    return Card(
                      child: Container(
                        height: 60,
                        alignment: Alignment.centerLeft,
                        child: Text("Item ${dataList[index]} $index"),
                      ),
                    );
                  },
                  childCount: (dataList.length >= pageSize)
                      ? dataList.length + 1
                      : dataList.length,
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

类结构

`MyRefreshDemoPage`:

  • 这是一个`StatefulWidget`,意味着它有状态并且可以动态更新界面。
  • 其对应的状态类是`MyRefreshDemoPageState`。

`MyRefreshDemoPageState`:

  • 包含应用程序的状态逻辑和界面构建。
  • 使用`ScrollController`来监听滚动事件。
  • 定义了两个主要的异步方法:`onRefresh`和`loadMore`,分别用于处理刷新和加载更多的数据。

相关代码分析

CupertinoSliverRefreshControl

  • 通过`CupertinoSliverRefreshControl`实现下拉刷新。
  • `onRefresh`方法模拟了一个2秒的延迟,然后清空数据列表并添加新的数据项,最后调用`setState`更新界面。

`CupertinoSliverRefreshControl` 是 Flutter 提供的一个用于实现下拉刷新控件的 Cupertino 风格组件,适用于 iOS 风格的应用。它通常用于 `CustomScrollView` 中,以实现类似于 iOS 的下拉刷新效果。

基本特性

  • 样式:模仿 iOS 的下拉刷新样式,与 `Cupertino` 系列组件一致,提供了典型的流畅过渡和回弹效果。
  • 集成:通常与 `CustomScrollView` 和其他 `Sliver` 组件一起使用。
主要属性
1.`refreshTriggerPullDistance`:
  • 是触发刷新的拉动距离。
  • 当用户向下拉动的距离超过这个值时,`onRefresh` 回调函数将被触发。
2.`refreshIndicatorExtent`:
  • 是刷新指示器显示的最大距离。
  • 在用户拉动超过 `refreshTriggerPullDistance` 后,指示器将扩展到这个距离。
3.`onRefresh`:
  • 类型为 `Future Function()` 的回调函数。
  • 当下拉操作触发刷新时,该函数被调用。
  • 通常在此函数中执行异步操作(如获取数据),完成后刷新指示器会自动收回。

注意事项
  • 物理滚动效果:通常与 `BouncingScrollPhysics` 一起使用,以获得更好的用户体验。
  • 兼容性:`CupertinoSliverRefreshControl` 主要用于 iOS 风格的应用,在 Android 平台上建议使用 `RefreshIndicator` 来保持风格一致。
  • 异步刷新处理:确保 `onRefresh` 中的异步操作完成后调用 `setState` 以更新 UI。

通过使用 `CupertinoSliverRefreshControl`,你可以在 Flutter 应用中轻松实现原生 iOS 风格的下拉刷新效果。

CustomScrollView

`CustomScrollView` 是 Flutter 提供的一个强大的滚动视图组件,它允许你创建一个包含多个不同类型的滚动子项(如列表、网格、头部等)的可滚动区域。通过使用 `CustomScrollView`,你可以实现复杂的、灵活的滚动布局,这在需要自定义滚动行为和组合多种子组件时非常有用。

基本概念
  • Slivers:`CustomScrollView` 的子组件是 “slivers”,它们是可以在滚动视图中动态缩放和展开的组件。常用的 slivers 有 `SliverList`、`SliverGrid`、`SliverAppBar` 等。
  • 灵活性:允许将不同类型的子组件组合在一起,支持复杂的滚动效果和布局。

常用的 Sliver 组件

1.`SliverAppBar`:
  • 支持可折叠的应用栏,可以在用户向下滚动时隐藏,向上滚动时显示。
  • 可以用来创建带有背景图片的动态头部。

2.`SliverList`:
  • 用于创建一个线性列表,类似于 `ListView`。
  • 通过 `SliverChildBuilderDelegate` 或 `SliverChildListDelegate` 来定义列表项。

3.`SliverGrid`:
  • 用于创建网格布局,类似于 `GridView`。
  • 可以通过 `SliverGridDelegate` 控制网格的布局样式。

4.`SliverToBoxAdapter`:
  • 用于将普通的 `Box` 组件(如 `Container`、`SizedBox`)包装成 sliver,方便在 `CustomScrollView` 中使用。

主要属性
`scrollDirection`:
  • 控制滚动的方向,默认为垂直方向(`Axis.vertical`)。
`reverse`:
  • 如果为 `true`,滚动视图的方向将被反转。
`controller`:
  • 可以设置一个 `ScrollController` 来控制滚动位置和监听滚动事件。
`physics`:
  • 控制滚动视图的物理特性,如弹性、阻尼等。常用的有 `BouncingScrollPhysics`、`ClampingScrollPhysics`。
'slivers':

允许开发者将多个 sliver 组件组合在一起,从而实现复杂的滚动布局。定义 `CustomScrollView` 的子组件,这些子组件可以是任何类型的 sliver。

常见的 Sliver 组件
1.`SliverAppBar`:
  • 用于创建可折叠的应用栏,支持滚动时的动态效果(如背景图片缩放)。
  • 可以设置为固定、浮动或完全可折叠。
2.`SliverList`:
  • 用于创建一个线性列表,类似于 `ListView`。
  • 可以通过 `SliverChildBuilderDelegate` 或 `SliverChildListDelegate` 动态或静态地生成子项。
3.`SliverGrid`:
  • 用于创建网格布局,类似于 `GridView`。
  • 通过 `SliverGridDelegate` 控制网格的布局样式。
4.`SliverToBoxAdapter`:
  • 用于将一个普通的 `Box` 组件包装成 sliver,允许在 sliver 列表中使用非 sliver 组件。
5.`SliverPadding`:
  • 用于在 sliver 组件周围添加内边距。
scrollController.position.pixels > 0 &&
                _scrollController.position.pixels ==
                    _scrollController.position.maxScrollExtent

上面代码是用于检测用户是否已经滚动到 `CustomScrollView` 或其他可滚动视图的底部。

`_scrollController.position.pixels`:
  • 这是 `ScrollController` 的一个属性,代表当前滚动视图顶部相对于其内容的滚动偏移量,单位为像素。
  • 当用户向下滚动时,这个值会增加。

`_scrollController.position.maxScrollExtent`:
  • 这是滚动视图内容的最大滚动范围,即内容的总高度减去视图的高度。
  • 当滚动视图滚动到最底部时,`pixels` 的值会等于 `maxScrollExtent`。

逻辑条件:
  • `(_scrollController.position.pixels > 0)`: 这保证了滚动视图至少已经向下滚动了一点(即不在顶部)。
  • `(_scrollController.position.pixels == _scrollController.position.maxScrollExtent)`: 这表示滚动视图已经滚动到了底部。

上面代码通常用于实现上拉加载更多数据的功能。当用户滚动到列表底部时,你可以通过这个条件来触发加载更多数据的操作。具体实现中,通常会在 `NotificationListener` 中监听 `ScrollNotification`,并在满足条件时调用加载方法。

NotificationListener

`NotificationListener` 是 Flutter 中用于监听树状结构中各种通知事件的一个组件。它可以监听从子树中冒泡上来的通知,并在检测到特定类型的通知时执行回调函数。

基本概念
  • 通知机制:Flutter 中的通知是一种在子树中传递信息的机制,通常用于处理全局事件或状态变化。
  • 冒泡事件:通知会从发送它的子组件开始向上冒泡,通过组件树传递直到被捕获或到达根节点。
常见用途
  • 滚动事件监听:最常见的用途之一是监听滚动事件,例如检测用户滚动到列表底部以加载更多数据。
  • 尺寸变化:监听某些组件的尺寸或布局变化通知。
  • 自定义通知:开发者可以定义自己的通知类型以便在组件树中传递自定义事件。

主要属性
`onNotification`:
  • 类型为 `bool Function(T notification)` 的回调函数。
  • 在通知被捕获时调用,接收一个通知对象作为参数。
  • 返回值决定了通知是否继续向上冒泡。返回 `true` 则通知停止向上冒泡,返回 `false` 则继续。
`child`:
  • `NotificationListener` 的子组件。
  • 通常是一个包含滚动组件或其他可能发出通知的组件。

关键点
  • 类型参数 `T`:`NotificationListener` 是一个泛型组件,可以指定要监听的通知类型。例如,`NotificationListener` 监听滚动通知。
  • 过滤通知:通过指定泛型参数,只监听特定类型的通知,其他类型的通知将被忽略。
  • 事件处理:在 `onNotification` 回调中处理捕获的事件,决定是否阻止通知继续冒泡。
注意事项
  • 确保返回值的正确性:返回 `true` 会阻止通知继续传播,通常需要谨慎使用。
  • `NotificationListener` 可以嵌套使用,在不同层级捕获并处理不同的通知。
  • 如果需要自定义通知,可以继承 `Notification` 类,定义自己的通知类型并在合适的地方发送。

SliverSafeArea

`SliverSafeArea` 是 Flutter 提供的一个用于在 `CustomScrollView` 中处理屏幕安全区域的组件。它的作用与 `SafeArea` 类似,但专门用于 sliver 系统,以确保在具有如刘海屏或圆角屏幕的设备上,内容不会被遮挡。

基本概念
  • 安全区域:指的是设备的可视区域,排除了可能遮挡内容的部分,如状态栏、导航栏、底部操作栏(如 iPhone X 的 Home Indicator 区域)。
  • Slivers:`SliverSafeArea` 是专为 sliver 系统设计的安全区域处理器,适用于 `CustomScrollView` 等使用 sliver 构建的滚动视图。
主要属性
`sliver`:
  • `SliverSafeArea` 的子组件,通常是其他 sliver 组件,如 `SliverList`、`SliverGrid` 等。
  • `left`、`top`、`right`、`bottom`:
  • 布尔值,默认为 `true`,用于指定是否在相应的边缘应用安全区域补白。
  • 例如,`top: false` 将不会在顶部应用安全区域补白。
`minimum`:
  • 设置每个边缘的最小补白,通过 `EdgeInsets` 指定。
  • 即使设备没有安全区域,这些最小补白也会被应用。
`maintainBottomViewPadding`:
  • 默认为 `false`。
  • 如果为 `true`,则当键盘出现时,仍然保持底部的安全区域补白。

使用场景
  • 刘海屏处理:在刘海屏设备上,确保内容不被屏幕的非矩形部分遮挡。
  • 统一样式:在不同设备上保持一致的内容展示效果,避免被状态栏或其他系统 UI 遮挡。
  • 滚动视图:在 `CustomScrollView` 中使用 slivers 时,确保应用安全区域的最佳方式。

注意事项
  • `SliverSafeArea` 是专为 `CustomScrollView` 和 sliver 体系设计的,使用时请确保其子组件也是 sliver。
  • 对于非 sliver 的视图,可以使用 `SafeArea` 来实现类似的功能。
  • 在设计布局时考虑不同设备的安全区域差异,确保用户体验一致。

SliverList

`SliverList` 是 Flutter 中用于在 `CustomScrollView` 中创建线性列表的一种 sliver 组件。它的功能类似于 `ListView`,但更加灵活,适合在需要更多自定义滚动效果的场景中使用。

基本概念
  • Slivers:在 Flutter 中,sliver 是一种可以在滚动视图中动态缩放和展开的组件。`SliverList` 是其中一种,用于创建可滚动的线性列表。
  • 自定义滚动视图:`SliverList` 通常与 `CustomScrollView` 搭配使用,以实现复杂的滚动效果和布局。
主要属性
`delegate`:
  • `SliverChildDelegate` 的一个实例,用来提供 `SliverList` 的子项。
有两种常用的子类:
  • `SliverChildBuilderDelegate`:适用于具有大量或动态生成的子项,通过一个回调函数构建子项。
  • `SliverChildListDelegate`:适用于数量固定且已知的子项,通过一个固定列表提供子项。

工作原理
  • 动态构建:`SliverChildBuilderDelegate` 按需创建子项。只有当子项需要显示时,它们才会被构建,适合处理大数据列表。
  • 固定列表:`SliverChildListDelegate` 适合处理小而固定的列表,因为所有子项会在初始化时被创建。
使用场景
  • 自定义滚动效果:用于需要实现特殊滚动效果的场景,如滚动头部、分页加载等。
  • 大数据列表:与 `SliverChildBuilderDelegate` 结合使用以处理大数据集。
  • 组合布局:可以与其他 sliver 一起使用,实现复杂的 UI 组合,如合并列表、网格、固定头部等。

注意事项
  • 性能:`SliverChildBuilderDelegate` 提供的懒加载机制可以显著提高性能,特别是在处理大数据集时。
  • 可扩展性:`SliverList` 可以与其他 sliver 组件(如 `SliverGrid`、`SliverAppBar`)混合使用,实现多样化的布局。
  • 布局限制:`SliverList` 必须在 `CustomScrollView` 或其他支持 sliver 的组件中使用。

通过利用 `SliverList`,开发者可以在 Flutter 中创建灵活且高性能的滚动列表,特别是在需要自定义滚动行为和布局的场景中。

SliverChildBuilderDelegate

`SliverChildBuilderDelegate` 是 Flutter 中用于动态构建 sliver 子组件的一个委托类。它通常与 `SliverList` 或 `SliverGrid` 一起使用,提供一种懒加载的方式来创建子组件,适合处理大数据列表或动态生成的子项。

基本概念
  • 懒加载:`SliverChildBuilderDelegate` 不会一次性构建所有子项,而是根据需要动态创建。当用户滚动到需要显示新子项时,才会调用构建函数生成子项。
  • 高效:这种方式减少了内存消耗和构建开销,特别是在处理大量子项时,这种高效的机制可以显著提高性能。

主要属性
`builder`:
  • 类型为 `IndexedWidgetBuilder`,一个回调函数,用于构建每个子项。
  • 函数签名为 `(BuildContext context, int index)`,其中 `index` 是当前构建的子项索引。
`childCount`:
  • 指定总共有多少个子项。
  • 如果为 `null`,表示子项数量不受限制,但 `builder` 必须处理 `index` 超过数据范围的情况。
`findChildIndexCallback`:
  • 类型为 `ChildIndexGetter`,用于在需要时查找指定 key 的索引。
  • 这在需要保持子项状态或支持滚动到特定项时非常有用。

工作原理
  • 动态生成:当 `CustomScrollView` 需要显示新子项时,`SliverChildBuilderDelegate` 调用 `builder` 函数生成子项。
  • 按需加载:仅在用户滚动到相应位置时才创建子项,从而优化了性能和内存使用。

使用场景
  • 大数据列表:特别适用于需要展示大量数据的情况,如长列表。
  • 动态内容:适合用于数据源动态变化的场景,比如从网络加载的内容。
  • 高性能要求:在需要高性能的应用中,使用 `SliverChildBuilderDelegate` 可以显著减少不必要的资源消耗。

注意事项
  • 确保 `builder` 函数能够高效地构建子项。
  • 当 `childCount` 为 `null` 时,`builder` 应该能够处理 `index` 超出范围的情况(例如返回 `null`)。
  • 如果需要在子项之间共享状态或保持状态,请确保正确地管理状态,可能需要使用 `Key` 或其他

BouncingScrollPhysics

`BouncingScrollPhysics` 是 Flutter 中的一种滚动物理效果,用于定义滚动视图在用户滚动到边界时的反弹行为。它模仿了 iOS 上的滚动惯性和边界反弹效果,这种效果在 iOS 应用中非常常见。

基本概念
  • 滚动物理:滚动物理类定义了滚动行为的物理特性,如惯性、阻尼和边界行为。
  • 边界反弹:`BouncingScrollPhysics` 特别适用于需要在内容到达边界时显示反弹效果的场景,用户体验类似于 iOS 的滚动视图。

主要特点
  • 反弹效果:当用户滚动超出内容边界时,内容会有一个自然的反弹效果,给人一种弹性和流畅的感觉。
  • 惯性滚动:滚动停止时的惯性行为模拟真实世界的物理效果,使得滚动体验更加自然。

主要属性
parent`:
  • `ScrollPhysics` 的父级设置,如果有的话,允许组合不同的滚动物理效果。
  • 例如,可以将 `BouncingScrollPhysics` 与 `AlwaysScrollableScrollPhysics` 结合使用,以确保在任何情况下都能滚动。

使用场景
  • iOS 风格应用:特别适合在 iOS 风格的应用中使用,以提供一致的用户体验。
  • 弹性效果:需要在内容边界提供弹性滚动效果的应用场景。
     

注意事项
  • 平台一致性:默认情况下,Flutter 在 iOS 上会自动使用 `BouncingScrollPhysics`,而在 Android 上使用 `ClampingScrollPhysics`。如果希望在 Android 上也使用弹性效果,需要显式设置 `BouncingScrollPhysics`。
  • 组合使用:可以通过设置 `parent` 属性来组合不同的滚动物理效果,满足复杂的滚动需求。
  • 用户体验:在设计用户体验时,考虑目标平台的用户期望,以选择合适的滚动物理效果。例如,Android 用户通常不期待滚动反弹,因此在 Android 上默认没有这种效果。

原文地址:https://blog.csdn.net/zhangying1994/article/details/143701229

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!