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

【Flutter】Flutter局部刷新的几种方式

前言

在Flutter开发中,我们会根据一些状态的值来改变UI样式,setState也是我们常用的状态刷新方式;但是当我们的页面布局比较复杂的时候,我们再用setState的时候,整个页面就会重绘,比较影响APP的性能,这种场景我们就可以只更新局部的组件。

局部更新

我们可以只更新界面的某一个Widget,不需要更新全部的界面,提高加载速度和节约性能的开销,如果是列表,还能够提交流程度,等等。。。

1. setState() 方法

setState是Flutter最简单也是最直接方式了,我们可以把一下复杂的UI拆分封装成不同的Widget,然后在封转的Widget里面进行局部刷新。

示例:

/// 复杂的UI滑竿组件封装成一个单独的Widget
/// 滑竿
  Widget _customSlider() {
    double sliderWidth = kXTScreenUtil.screenWidth - 16 * 2;
    return XTModularNodeSlisder(
      key: _slisderStateKey,
      width: sliderWidth,
      bubbleUnit: "%",
      isShowBubble: true,
      alwaysDisplayBubble: true,
      itemData: _itemData!,
      onTapEnd: (value, ltvValue){
        _sliderValueChanged(ltvValue);
        _updateErrorTips();
      },
    );
  }

2. ValueNotifier 和 ValueListenableBuilder

ValueNotifier 是 Flutter 提供的一种轻量级状态管理工具,可以用于监听特定值的变化并刷新相关 UI。结合 ValueListenableBuilder,可以在特定值改变时触发局部刷新。

示例:

class ZFJWidget extends StatelessWidget {

  // vn
  final ValueNotifier<int> counter = ValueNotifier<int>(0);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ValueListenableBuilder<int>(
          valueListenable: counter,
          builder: (context, value, child) {
            // 仅刷新这个 Text widget
            return Text('$value');
          },
        ),
        ElevatedButton(
          onPressed: () {
            // 更新 ValueNotifier,局部刷新
            counter.value++;
          },
          child: Text('Increment'),
        ),
      ],
    );
  }
}

3. StreamBuilder

如果需要基于异步数据流进行刷新,StreamBuilder 是一个非常合适的工具。它会监听 Stream,当数据流更新时,局部的 widget 也会自动更新。
当 Stream 中的数据发生变化时,StreamBuilder 会重新构建相关的部分。

class ZFJWidget extends StatelessWidget {

  // 
  final Stream<int> counterStream = Stream<int>.periodic(Duration(seconds: 1), (x) => x);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<int>(
      stream: counterStream,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return Text('Count: ${snapshot.data}');
        } else {
          return CircularProgressIndicator();
        }
      },
    );
  }
}

4. InheritedWidget

InheritedWidget 是一种提供数据共享的方式,可以在 widget 树中共享状态,并通过该 widget 实现局部刷新。
比如下面的代码,当 Counter 中的数据改变时,它的子 widget 树会触发局部刷新。

示例:

class Counter extends InheritedWidget {
  final int count;

  Counter({Key? key, required this.count, required Widget child}) : super(key: key, child: child);

  static Counter of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<Counter>()!;
  }

  @override
  bool updateShouldNotify(Counter oldWidget) {
    return oldWidget.count != count;
  }
}

class ZFJWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Counter(
      count: 10,
      child: Column(
        children: [
          _ChildWidget(),
        ],
      ),
    );
  }
}

class _ChildWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final count = Counter.of(context).count;
    return Text('Count: $count');
  }
}

5. ChangeNotifier + Consumer(Provider)

通过 ChangeNotifier 和 Provider 实现状态管理与局部刷新。

class Counter extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

class CounterProviderWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Counter(),
      child: Column(
        children: [
          Consumer<Counter>(
            builder: (context, counter, child) {
              return Text('Counter: ${counter.count}');
            },
          ),
          ElevatedButton(
            onPressed: () {
              Provider.of<Counter>(context, listen: false).increment();
            },
            child: Text('Increment'),
          ),
        ],
      ),
    );
  }
}

6.RepaintBoundary

通过 RepaintBoundary 控制子 widget 的重绘范围,从而实现性能优化的局部刷新。

class RepaintBoundaryExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      child: Text('This part will be repainted independently'),
    );
  }
}

总结

上述几种方式可以根据不同的需求场景来选择。setState 是最基础的局部刷新,ValueNotifier 和 ChangeNotifier 等更适合状态管理场景,而 RepaintBoundary 则更注重性能优化。


http://www.kler.cn/news/310022.html

相关文章:

  • springboot+screw反向生成数据库说明文档
  • 【动态规划】
  • 23ai DGPDB,Oracle资源池战略的最后一块拼图
  • C++速通LeetCode简单第11题-对称二叉树
  • 【rust】rust条件编译
  • 【linux-Day3】linux的基本指令<中>
  • 打包部署若依(RuoYi)SpringBoot后端和Vue前端图文教程
  • pycv实时目标检测快速实现
  • 120页ppt丨集团公司战略规划内容、方法、步骤及战略规划案例研究
  • 分类预测|基于粒子群优化径向基神经网络的数据分类预测Matlab程序PSO-RBF 多特征输入多类别输出 含基础RBF程序
  • 【鸿蒙】HarmonyOS NEXT星河入门到实战8-自定义组件-组件通信
  • 江科大笔记—STM32课程简介
  • 基于SpringBoot+Vue+MySQL的家乡特色推荐系统
  • 英飞凌—TC377芯片详解(1)
  • npm包管理工具
  • UGit:腾讯自研的Git客户端新宠
  • Spring如何处理线程并发问题?
  • 传输层协议 —— UDP协议
  • LXDE lxpanel桌面环境中打开一个终端窗口 lxterminal
  • PHP 中传值与传引用的区别
  • 线程有哪几种状态?
  • web杂项
  • 腾讯云技术深度探索:构建高效云原生微服务架构
  • Java Stream API | Java Stream API 中 `filter()`的使用
  • TCP/IP Socket用于测试免费使用的服务器端
  • window下idea中scala的配置
  • web基础—dvwa靶场(五)File Upload
  • HarmonyOS开发之自定义构建函数
  • gi清除无用缓存
  • 【Elasticsearch系列】Elasticsearch中的分页