pro.user pro
Flutter, one of the most popular cross-platform framework for mobile apps development in 2020, had become in my preferred tool for my personal and work projects.
Flutter是2020年用于移动应用程序开发的最受欢迎的跨平台框架之一,已成为我个人和工作项目的首选工具。
Flutter is Google’s UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase.
Flutter是Google的UI工具包,可通过单个代码库为移动 , 网络和桌面构建漂亮的,本机编译的应用程序。
Flutter has its own state management system. Pretty sure you might hear before about setState which is the most used method inside your StatefulWidget.
Flutter有自己的状态管理系统。 可以肯定的是,您可能会听说过setState ,它是StatefulWidget中最常用的方法。
What if I tell you that there is another way to update the state of your widget without calling setState method. Don't get me wrong, there is nothing wrong with setState, like I said this is just another way.
如果我告诉您还有另一种无需调用setState方法即可更新小部件状态的方法。 不要误会我的意思, setState没什么问题,就像我说的那样。
You might be familiar with this.
您可能对此很熟悉。
class _MyWidget extends State<MyWidget> { int _count = 0; @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text( 'You had tapped $_count.', ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () => setState(() => _count++), ), ); }}So this is when ValueNotifier comes in. Flutter has a very long list of widgets already implemented just for you and ValueListenableBuilder is one of them.
因此,这是ValueNotifier出现的时候。Flutter已经为您实现了很长的小部件列表, ValueListenableBuilder就是其中之一。
ValueListenableBuilder( valueListenable: listenableValue, builder: (context, value child) => child,)ValueListenableBuilder has two required arguments. valueListenable which is an instance of ValueNotifier and builder which is a callback that builds the widget that depends on the value that is being listened. So your new code will look more less like this.
ValueListenableBuilder具有两个必需的参数。 valueListenable是ValueNotifier的实例,而builder是一个回调,该回调根据所侦听的值来构建窗口小部件。 因此,您的新代码看起来会更像这样。
class _MyWidget extends State<MyWidget> { ValueNotifier<int> _counter; @override void initState() { _counter = ValueNotifier<int>(0); super.initState(); } @override void dispose() { _counter.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: ValueListenableBuilder( valueListenable: _counter, builder: (context, value, child) => Text( 'You had tapped $value.', ), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () => _counter.value++, ), ); }}Feel free to try this code by your own. Believe me, works. But how? How Text widget get updated without calling setState method? so far known as the only method that can rebuild the UI base on the current state of the widget.
随意尝试自己编写此代码。 相信我,工作。 但是如何? 如何在不调用setState方法的情况下更新Text小部件? 迄今为止,这是唯一可以基于小部件的当前状态重建UI的方法。
Well if you are familiar with Observer programming pattern you might understand even better. Basically the widget ValueListenableBuilder is Listening (Observing) any change on the ValueListenable (Emitter) so it can rebuild the UI when changes are notified. The builder callback receives three arguments (context, value, child). At this point, I hope you might be familiar with the BuildContext object and what is for. The value will be the current value (after change) in the ValueNotifier<int> object (_counter). Notice that ValueNotifier is a generic class so its current value type will depends on its declaration. In this case value will be a int.
好吧,如果您熟悉Observer编程模式,则可能会更好地理解。 基本上,小部件ValueListenableBuilder小部件正在侦听(观察) ValueListenable (发射器)上的任何更改,因此它可以在通知更改时重建UI 。 构建器回调接收三个参数(上下文,值,子级)。 在这一点上,我希望您可能熟悉BuildContext对象及其用途。 该值将是ValueNotifier <int>对象( _counter )中的当前值(更改后)。 请注意, ValueNotifier是通用类,因此其当前值类型将取决于其声明。 在这种情况下, 值将为int 。
This approach, even if the code is little longer, is more efficient than previous one. Notice that the only part that is being repainted is the Text widget. For this example there is no need to rebuild the whole widget it self meaning the Scaffold, AppBar or even the FloatingActionButton who triggers the change.
即使代码稍长一点,这种方法也比以前的方法更有效。 请注意,唯一要重绘的部分是“ 文本”小部件。 对于此示例,无需重建整个窗口小部件,它本身即意味着触发更改的Scaffold , AppBar甚至FloatingActionButton 。
No, I didn't forget about child. The child argument makes the building process even more efficient. You might be on situations when builder callback has a very complex tree of widgets but only part of it depends on the value.
不,我没有忘记孩子 。 child参数使构建过程更加高效。 您可能会遇到以下情况:构建器回调具有非常复杂的窗口小部件树,但其中只有一部分取决于值 。
ValueListenableBuilder( valueListenable: _counter, builder: (context, value, child) => Container( width: 200, height: 200, color: value % 2 == 0 ? Colors.blue : Colors.red, alignment: Alignment.center, child: child, ), child: Container( color: Colors.green, width: 100, height: 100, ),)Notice that the color of Container inside the builder change depending on the value but does not affect any property on the child Container, so no need to rebuild it.
请注意,构建器内部的Container的颜色根据值而变化,但不会影响子Container的任何属性,因此无需重建它。
You might find yourself in situation when ValueNotifier is not enough for your business logic. Well, you can of course create your own notifier.
当ValueNotifier不足以满足您的业务逻辑时,您可能会遇到麻烦 。 好吧,您当然可以创建自己的通知程序。
class MyCustomNotifier extends ValueNotifier<bool> { MyCustomNotifier({bool value}) : super(value ?? false); void toggle() { // Add your super logic here! value = !value; }}class _MyWidget extends State<MyWidget> { MyCustomNotifier _notifier; @override void initState() { _notifier = MyCustomNotifier(); super.initState(); } @override void dispose() { _notifier.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: ValueListenableBuilder<bool>( valueListenable: _notifier, builder: (context, value, child) => Container( width: 200, height: 200, color: value ? Colors.blue : Colors.red, alignment: Alignment.center, child: child, ), child: Container( color: Colors.green, width: 100, height: 100, ), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () => _notifier.toggle(), ), ); }}And last but not least important. Since the ValueNotifier is a disposable value you must take care of it when your widget is disposed. The dispose method on the notifier will release any subscribed listener avoiding any memory leak in your app.
最后但并非最不重要的一点。 由于ValueNotifier是可抛弃的值,因此在处置窗口小部件时必须照顾好它。 通知程序上的dispose方法将释放所有订阅的侦听器,从而避免应用程序中的任何内存泄漏。
Since Flutter proved so far that is able to render very fast large tree of widgets, both solutions are correct in my opinion. I guess is matter of choice and some special situation when ValueNotifier might come handy in order to keep the code readable when the state of the widget holds many data at once.
到目前为止,由于Flutter证明能够渲染非常大的小部件树,因此我认为这两种解决方案都是正确的。 我猜想是选择问题,还有一些特殊情况,当小部件的状态一次包含许多数据时, ValueNotifier可能会派上用场,以使代码可读。
What do you think?
你怎么看?
PS: Please forget my English skills I am a Spanish native speaker but doing my best to bring to you my humble knowledge.
PS:请忘记我的英语技能,我会说西班牙语,但会尽我最大的努力为您带来我的拙劣知识。
翻译自: https://medium.com/@krel0024/use-valuenotifier-like-pro-6441d9ddad05
pro.user pro