Flutter组件ValueListenableBuilder使用#yyds干货盘点#

不飞则已,一飞冲天;不鸣则已,一鸣惊人。这篇文章主要讲述Flutter组件ValueListenableBuilder使用#yyds干货盘点#相关的知识,希望能为你提供帮助。
【Flutter组件ValueListenableBuilder使用#yyds干货盘点#】

作者:坚果
公众号:"??大前端之旅??"
华为云享专家,InfoQ签约作者,阿里云专家博主,51CTO博客首席体验官,??开源项目GVA成员之一??,专注于大前端技术的分享,包括Flutter,小程序,安卓,VUE,javascript。
如下使用 ??ValueListenableBuilder?? 组件,监听 ??_counter?? 对象,当该可监听对象的数值变化时,会可以通知监听者,重新构建 ??builder?? 方法里的组件。这样最大的好处在于:??不需要 ??通过 ??_MyHomePageState#setState?? 对内部整体进行构建,仅对需要??改变的局部??进行重新构建。

InheritedWidget 提供一种在 widget 树中从上到下共享数据的方式,但是也有很多场景数据流向并非从上到下,比如从下到上或者横向等。为了解决这个问题,Flutter 提供了一个 ValueListenableBuilder 组件,它的功能是监听一个数据源,如果数据源发生变化,则会重新执行其 builder,定义如下:
const ValueListenableBuilder(
Key? key,
required this.valueListenable, // 数据源,类型为ValueListenable< T>
required this.builder, // builder
this.child,

  • valueListenable:类型为 ??ValueListenable< T> ??,表示一个可监听的数据源。
  • builder:数据源发生变化通知时,会重新调用 builder 重新 build 子组件树。
  • child: builder 中每次都会重新构建整个子组件树,如果子组件树中有一些不变的部分,可以传递给child,child 会作为builder的第三个参数传递给 builder,通过这种方式就可以实现组件缓存,原理和AnimatedBuilder 第三个 child 相同。
示例
我们依然实现一个计数器,点击
main.dart
import package:flutter/material.dart;

import provider.dart;

void main()
runApp(const MyApp());


class MyApp extends StatelessWidget
const MyApp(Key? key) : super(key: key);

@override
Widget build(BuildContext context)
return MaterialApp(
title: Flutter Demo,
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: Flutter Demo Home Page),
);



class MyHomePage extends StatefulWidget
const MyHomePage(Key? key, required this.title) : super(key: key);

final String title;

@override
State< MyHomePage> createState() => _MyHomePageState();


class _MyHomePageState extends State< MyHomePage>
final ValueNotifier< int> _counter = ValueNotifier(0);

void _incrementCounter()
_counter.value++;


@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
IconButton(onPressed: _toSetting, icon: const Icon(Icons.settings))
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: < Widget> [
const Text(
You have pushed the button this many times:,
),
ValueListenableBuilder(
valueListenable: _counter,
builder: (ctx, int value, __) => Text(
$value,
style: Theme.of(context).textTheme.headline4,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: Increment,
child: const Icon(Icons.add),
),
);


@override
void dispose()
super.dispose();
_counter.dispose();


void _toSetting()
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SettingPage(
counter: _counter,
)));


provider.dart
import package:flutter/foundation.dart;
import package:flutter/material.dart;

class SettingPage extends StatelessWidget
final ValueNotifier< int> counter;

const SettingPage(
Key? key,
required this.counter,
) : super(key: key);

void _onReset()
counter.value = https://www.songbingjia.com/android/0;


@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: const Text(设置界面),
),
body: Container(
height: 54,
color: Colors.white,
child: Row(
children: [
const SizedBox(
width: 10,
),
ValueListenableBuilder(
valueListenable: counter,
builder: (ctx, int value, __) => Text(
当前计数为: $value,
),
),
const Spacer(),
ElevatedButton(
child: const Text(重置),
onPressed: _onReset,
),
const SizedBox(
width: 10,
)
],
),
),
);


因此我们有一个建议就是:尽可能让 ValueListenableBuilder 只构建依赖数据源的widget,这样的话可以缩小重新构建的范围,也就是说 ValueListenableBuilder 的拆分粒度应该尽可能细。
总结
关于 ValueListenableBuilder 有两点需要了解:
  1. 和数据流向无关,可以实现任意流向的数据共享。
  2. 实践中,ValueListenableBuilder 的拆分粒度应该尽可能细,可以提高性能。
其实前面的 ??ValueListenableBuilder?? 的效果以及不错了,但是在某些场合仍存在不足。因为 ??_counter?? 需要通过构造方法进行传递,如果状态量过多,或共享场合变多、传递层级过深,也会使代码处理比较复杂。最致命的一点是:??业务逻辑处理??和??界面组件??都耦合在 ??_MyHomePageState?? 中,这对于??拓展??和??维护??而言并不是件好事。所以 ??管理 ?? 对于 ??复杂逻辑性下的状态的共享及修改同步?? 是有必要的。
文档地址:https://api.flutter.dev/flutter/widgets/ValueListenableBuilder-class.html


    推荐阅读