Flutter下拉刷新及专业功能插件pull_to_refresh_pro的使用

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

Flutter下拉刷新及专业功能插件pull_to_refresh_pro的使用

介绍

pull_to_refresh_pro 是一个提供上拉加载和下拉刷新的组件, 同时支持Android和iOS。

特性

  • 提供上拉加载和下拉刷新
  • 几乎适合所有部件
  • 提供全局设置默认指示器和属性
  • 提供多种比较常用的指示器
  • 支持Android和iOS默认滑动引擎,可限制越界距离, 打造自定义弹性动画, 速度, 阻尼等。
  • 支持水平和垂直刷新, 同时支持翻转列表(四个方向)
  • 提供多种刷新指示器风格: 跟随, 不跟随, 位于背部, 位于前部, 提供多种加载更多风格
  • 提供二楼刷新, 可实现类似淘宝二楼, 微信二楼, 携程二楼
  • 允许关联指示器存放在Viewport外部, 即朋友圈刷新效果

用法

  1. 添加依赖到 pubspec.yaml
dependencies:
  pull_to_refresh_pro: ^0.0.1
  1. 导入库
import 'package:pull_to_refresh_pro/pull_to_refresh_pro.dart';
  1. 简单例子
List<String> items = ["1", "2", "3", "4", "5", "6", "7", "8"];
RefreshController _refreshController = RefreshController(initialRefresh: false);

void _onRefresh() async {
  // 监听网络请求
  await Future.delayed(Duration(milliseconds: 1000));
  // 如果失败, 使用 refreshFailed()
  _refreshController.refreshCompleted();
}

void _onLoading() async {
  // 监听网络请求
  await Future.delayed(Duration(milliseconds: 1000));
  // 如果失败, 使用 loadFailed(), 如果无数据返回, 使用 LoadNodata()
  items.add((items.length + 1).toString());
  if (mounted)
    setState(() {});
  _refreshController.loadComplete();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: SmartRefresher(
      enablePullDown: true,
      enablePullUp: true,
      header: WaterDropHeader(),
      footer: CustomFooter(
        builder: (BuildContext context, LoadStatus mode) {
          Widget body;
          if (mode == LoadStatus.idle) {
            body = Text("上拉加载");
          } else if (mode == LoadStatus.loading) {
            body = CupertinoActivityIndicator();
          } else if (mode == LoadStatus.failed) {
            body = Text("加载失败!点击重试!");
          } else if (mode == LoadStatus.canLoading) {
            body = Text("松手, 加载更多!");
          } else {
            body = Text("没有更多数据了!");
          }
          return Container(
            height: 55.0,
            child: Center(child: body),
          );
        },
      ),
      controller: _refreshController,
      onRefresh: _onRefresh,
      onLoading: _onLoading,
      child: ListView.builder(
        itemBuilder: (c, i) => Card(child: Center(child: Text(items[i]))),
        itemExtent: 100.0,
        itemCount: items.length,
      ),
    ),
  );
}
  1. 全局配置 RefreshConfiguration, 配置子树下的所有 SmartRefresher 表现, 一般存放于 MaterialApp 的根部, 用法和 ScrollConfiguration 是类似的。
RefreshConfiguration(
  headerBuilder: () => WaterDropHeader(), // 配置默认头部指示器
  footerBuilder: () => ClassicFooter(), // 配置默认底部指示器
  headerTriggerDistance: 80.0, // 头部触发刷新的越界距离
  springDescription: SpringDescription(stiffness: 170, damping: 16, mass: 1.9), // 自定义回弹动画
  maxOverScrollExtent: 100, // 头部最大可以拖动的范围
  maxUnderScrollExtent: 0, // 底部最大可以拖动的范围
  enableScrollWhenRefreshCompleted: true, // 在刷新完成后是否可以继续滚动
  enableLoadingWhenFailed: true, // 在加载失败的状态下, 用户仍然可以通过手势上拉来触发加载更多
  hideFooterWhenNotFull: false, // 当Viewport不满一屏时, 禁用上拉加载更多功能
  enableBallisticLoad: true, // 可以通过惯性滑动触发加载更多
  child: MaterialApp(
    // 其他配置...
  ),
);
  1. 1.5.6 新增国际化处理特性, 你可以在 MaterialApp 或者 CupertinoApp 追加如下代码:
MaterialApp(
  localizationsDelegates: [
    // 这行是关键
    RefreshLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalMaterialLocalizations.delegate
  ],
  supportedLocales: [
    const Locale('en'),
    const Locale('zh'),
  ],
  localeResolutionCallback: (Locale locale, Iterable<Locale> supportedLocales) {
    return locale;
  },
);

对SmartRefresher里child详细说明

自1.4.3, child 属性从 ScrollView 转变为 Widget, 但是这并不意味着对于所有 Widget 处理是一样的。SmartRefresher 内部实现机制并非是类似于 NestedScrollView

这里的处理机制分为两个大类:

  • 第一类是继承于 ScrollView 的那一类组件, 目前来说, 就只有这三种: ListView, GridView, CustomScrollView
  • 第二类是非继承于 ScrollView 的那类组件, 一般是存放空视图, 非滚动视图(非滚动转化为滚动), PageView, 无需你自己通过 LayoutBuilder 估计高度。

对于第一类的处理机制是从内部"非法"取出 slivers。第二类, 则是把 child 直接放进类似于 SliverToBoxAdapter。通过前后拼接 headerfooter 组成 slivers, 然后 SmartRefresher 内部把 slivers 放进 CustomScrollView

更多

  • 属性文档 或者 Api/Doc
  • 自定义指示器
  • 指示器内部属性介绍
  • 更新日志
  • 注意地方
  • 常见问题

暂时存在的问题

  • 关于配合 NestedScrollView 一起使用, 会出现很多奇怪的现象, 当你下滑然后快速上滑, 它会出现跳动, 主要是 NestedScrollView 没有考虑到在 BouncingScrollPhysics 下的越界问题, 相关 flutter issue: 34316, 33367, 29264, 这个问题只能等待 flutter 修复。
  • SmartRefresher 不具有向子树下的 ScrollView 注入刷新功能, 也就是说如果直接把 AnimatedList, RecordableListView 放在 child 结点是不行的, 这个问题我尝试过很多个方法都失败了, 由于实现原理, 我必须得在 slivers 头部和尾部追加, 实际上, 这个问题也不是我组件的问题, 比如说 AnimatedList, 假如我要结合 AnimatedListGridView 一起使用是没办法的, 唯有把 AnimatedList 转换为 SliverAnimatedList 才能解决。目前呢, 面对这种问题的话, 我已经有临时的解决方案, 但有点麻烦, 要重写它内部的代码, 然后在 ScrollView 外部增加 SmartRefresher

感谢

开源协议

MIT License

Copyright (c) 2018 Jpeng

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

更多关于Flutter下拉刷新及专业功能插件pull_to_refresh_pro的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter下拉刷新及专业功能插件pull_to_refresh_pro的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用pull_to_refresh_pro插件来实现下拉刷新功能的代码示例。pull_to_refresh_pro是一个功能强大的刷新插件,支持多种刷新样式和丰富的自定义选项。

首先,确保你已经在pubspec.yaml文件中添加了pull_to_refresh_pro依赖:

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

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

接下来是一个完整的Flutter应用示例,展示了如何使用pull_to_refresh_pro来实现下拉刷新功能:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Pull To Refresh Pro Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  final RefreshController _refreshController = RefreshController();
  List<String> _items = List.generate(20, (index) => "Item ${index + 1}");

  @override
  void initState() {
    super.initState();
    // 监听刷新状态变化
    _refreshController.addListener(() {
      if (_refreshController.refreshState == RefreshState.Idle &&
          _refreshController.loadState == RefreshState.Idle) {
        // 刷新或加载完成时的一些处理
      }
    });
  }

  @override
  void dispose() {
    _refreshController.dispose();
    super.dispose();
  }

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

    // 更新数据
    setState(() {
      _items = List.generate(20, (index) => "Refreshed Item ${index + 1}");
    });

    // 通知刷新完成
    _refreshController.refreshCompleted();
  }

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

    // 更新数据
    setState(() {
      _items.addAll(List.generate(10, (index) => "Loaded Item ${_items.length + index + 1}"));
    });

    // 通知加载完成
    _refreshController.loadComplete();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Pull To Refresh Pro Demo'),
      ),
      body: SmartRefresher(
        controller: _refreshController,
        enablePullDown: true,
        enablePullUp: true,
        header: WaterDropHeader(), // 下拉刷新头部
        footer: ClassicsFooter(), // 上拉加载底部
        onRefresh: _onRefresh,
        onLoad: _onLoad,
        child: ListView.builder(
          itemCount: _items.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(_items[index]),
            );
          },
        ),
      ),
    );
  }
}

在这个示例中,我们使用了SmartRefresher组件来包裹我们的ListView,并设置了下拉刷新和上拉加载的头部和底部样式。通过onRefreshonLoad回调来处理刷新和加载的逻辑。

  • WaterDropHeader是一个下拉刷新头部的样式,你可以根据需要选择其他样式,如MaterialHeader或自定义样式。
  • ClassicsFooter是一个上拉加载底部的样式,同样,你也可以选择其他样式或自定义。

确保你导入了必要的包,并替换pull_to_refresh_pro的版本号为最新的版本。这样,你就可以在Flutter应用中实现下拉刷新和上拉加载的功能了。

回到顶部