当前位置: 首页 > article >正文

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

方式一:RefreshIndicator+ListView实现

import 'package:flutter/material.dart';

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

  @override
  State<StatefulWidget> createState() {
    return _SimpleRefreshDemoPage();
  }
}

class _SimpleRefreshDemoPage extends State<SimpleRefreshDemoPage> {
  final int pageSize = 50;

  bool disposed = false;

  List<String> dataList = [];

  final ScrollController _scrollController = ScrollController();

  final GlobalKey<RefreshIndicatorState> refreshKey = GlobalKey();

  Future<void> onRefresh() async {
    await Future.delayed(const Duration(seconds: 4));
    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: 4));
    for (int i = 0; i < pageSize; i++) {
      dataList.add("loadmore");
    }
    if (disposed) {
      return;
    }
    setState(() {});
  }

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        loadMore();
      }
    });

    Future.delayed(const Duration(seconds: 0), () {
      refreshKey.currentState?.show();
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("SimpleRefreshDemoPage"),
      ),
      body: RefreshIndicator(
        key: refreshKey,
        onRefresh: onRefresh,
        child: ListView.builder(
          physics: const AlwaysScrollableScrollPhysics(),
          itemBuilder: (context, 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"),
              ),
            );
          },
          itemCount: (dataList.length >= pageSize)
              ? dataList.length + 1
              : dataList.length,
          controller: _scrollController,
        ),
      ),
    );
  }
}

 如何实现下拉刷新       

 RefreshIndicator

        RefreshIndicator 是 Flutter 中用于实现下拉刷新功能的一个组件。RefreshIndicator 包裹一个可滚动的子组件,如 `ListView` 或 `GridView`,当用户下拉到列表顶部时,会触发刷新操作。上面的例子中RefreshIndicator包裹在了ListView。

        `onRefresh` 是一个返回 `Future` 的异步函数,用于执行刷新操作。

        关键属性

  • onRefresh`: 必须实现的回调函数,定义刷新时的操作。
  • `child`: 需要包裹的可滚动子组件。
  • `color`: 刷新指示器的进度条颜色。
  • `backgroundColor`: 刷新指示器的背景色。
  • `displacement`: 指示器开始显示时与顶部的距离。

如何实现下拉加载

ScrollController

   _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        loadMore();
      }
    });

如何检测用户是否滚动到了 `ScrollView` 的底部?

_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent

_scrollController.position.pixels` :表示当前滚动的位置。

`_scrollController.position.maxScrollExtent` :表示可滚动区域的最大值。

上面两个值相等时,说明用户已经滚动到了底部。

`bool disposed` 字段作用

        在上面的代码中,`bool disposed` 字段用于指示 `State` 对象是否已经被销毁。当 `dispose` 方法被调用时,`disposed` 被设置为 `true`。这个字段主要用于在异步操作完成后,确保不会调用已经被销毁的 `State` 对象的 `setState` 方法。

作用分析

1.防止在销毁后调用 `setState`:
  • 异步操作(如 `Future.delayed`)在完成后,可能会尝试调用 `setState` 来更新 UI。然而,如果在异步操作执行期间,用户已经导航离开了当前页面,导致 `State` 对象被销毁,那么调用 `setState` 就会抛出异常,因为 `State` 已经不再是活动的。
  • 通过检查 `disposed` 字段,可以在调用 `setState` 前确认 `State` 是否仍然有效,从而避免在组件销毁后对其进行不必要的更新。
2.提高代码的稳健性:
  • 这种模式是一种防御性编程的方法,确保应用程序在面对不确定的异步执行时仍然是稳定的。
 @override
  void dispose() {
    disposed = true;
    super.dispose();
  }

  

  Future<void> onRefresh() async {
    await Future.delayed(const Duration(seconds: 4));
    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: 4));
    for (int i = 0; i < pageSize; i++) {
      dataList.add("loadmore");
    }
    if (disposed) {
      return;
    }
    setState(() {});
  }

在 `onRefresh` 和 `loadMore` 方法中,`disposed` 被用来检查 `State` 是否已经被销毁。如果 `disposed` 为 `true`,则不再调用 `setState`,从而避免可能的异常。


3.总结


使用 `disposed` 字段可以有效地防止在组件销毁后进行不必要或有害的 UI 更新。这种模式特别适用于涉及异步操作的 Flutter 应用开发,确保代码在处理 `State` 生命周期时更加健壮。

        在 Flutter 中,`dispose` 方法是一个非常重要的生命周期方法,用于在不再需要一个对象时释放资源。通常,`dispose` 方法用于清理那些可能导致内存泄漏的资源,如控制器、监听器和订阅等。

 `dispose` 方法的常规用途

`dispose` 方法在 `StatefulWidget` 的状态对象中被重写。它在以下情况下被调用:

  • Widget 被从树中永久移除时。
  • 需要释放资源以避免内存泄漏时。

`dispose` 方法的典型用法

1.释放控制器:
  • 常用于释放 `AnimationController`、`TextEditingController`、`PageController` 等控制器。
2.取消订阅:
  • 用于取消流(stream)的订阅,以防止内存泄漏。
3.移除监听器:
  • 移除添加到某些对象上的监听器,例如 `ScrollController` 的监听器。

重要注意事项

  • 调用 `super.dispose()`:在重写 `dispose` 方法时,确保在最后调用 `super.dispose()`。这会调用父类的 `dispose` 方法,完成必要的清理。
  • 确保资源释放:所有在 `initState` 或其他地方创建的需要手动管理的资源,都应在 `dispose` 中被正确释放。
  • 流的取消:对于任何流的订阅,一定要在 `dispose` 中调用 `cancel` 方法。

通过正确使用 `dispose` 方法,你可以确保你的应用程序以更高效的方式管理内存,避免可能的内存泄漏问题。

       


http://www.kler.cn/a/381274.html

相关文章:

  • 小菜家教平台:基于SpringBoot+Vue打造一站式学习管理系统
  • Scala的属性访问权限(一)默认访问权限
  • 【进度猫-注册/登录安全分析报告】
  • C语言教程——操作符详解(2)
  • 我谈正态分布——正态偏态
  • Java解析word中的表格或者文本
  • 重学Android:从位运算到二进制表示(零)
  • QT pro项目工程的条件编译
  • vue--vueCLI
  • 企业CRM管理系统PHP源码/PHP客户关系CRM客户管理系统源码
  • 【Python】计算机视觉应用:OpenCV库图像处理入门
  • Python Pandas内存管理技巧助力高效处理大数据
  • 针对告警数量、告警位置、告警类型等参数进行统计,并做可视化处理的智慧能源开源了
  • 微服务架构面试内容整理-Ribbon
  • 通过Flink读写云原生数据仓库AnalyticDB PostgreSQL版(ADB PG)数据
  • LWIP通信协议UDP发送、接收源码解析
  • 使用JdbcTemplate 进行数据库的增、删、改、查
  • ServletContext 对象介绍
  • Redis持久化机制——针对实习面试
  • 力扣11.4
  • 微信小程序 基于协同过滤算法的的校园音乐推荐系统
  • 大客户营销数字销售实战讲师培训讲师唐兴通专家人工智能大模型销售客户开发AI大数据挑战式销售顾问式销售专业销售向高层销售业绩增长创新
  • 低代码解锁跨平台应用开发新境界
  • Elasticsearch核心概念
  • [渲染层网络层错误] net::ERR_CONTENT_LENGTH_MISMATCH 问题解决
  • 【TextIn:开源免费的AI智能文字识别产品(通用文档智能解析识别、OCR识别、文档格式转换、篡改检测、证件识别等)】