1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'package:flutter/animation.dart';
6/// @docImport 'package:flutter/material.dart';
7///
8/// @docImport 'async.dart';
9/// @docImport 'notification_listener.dart';
10/// @docImport 'text.dart';
11/// @docImport 'transitions.dart';
12/// @docImport 'tween_animation_builder.dart';
13library;
14
15import 'package:flutter/foundation.dart';
16
17import 'framework.dart';
18
19/// Builds a [Widget] when given a concrete value of a [ValueListenable<T>].
20///
21/// If the `child` parameter provided to the [ValueListenableBuilder] is not
22/// null, the same `child` widget is passed back to this [ValueWidgetBuilder]
23/// and should typically be incorporated in the returned widget tree.
24///
25/// See also:
26///
27/// * [ValueListenableBuilder], a widget which invokes this builder each time
28/// a [ValueListenable] changes value.
29typedef ValueWidgetBuilder<T> = Widget Function(BuildContext context, T value, Widget? child);
30
31/// A widget whose content stays synced with a [ValueListenable].
32///
33/// Given a [ValueListenable<T>] and a [builder] which builds widgets from
34/// concrete values of `T`, this class will automatically register itself as a
35/// listener of the [ValueListenable] and call the [builder] with updated values
36/// when the value changes.
37///
38/// {@youtube 560 315 https://www.youtube.com/watch?v=s-ZG-jS5QHQ}
39///
40/// ## Performance optimizations
41///
42/// If your [builder] function contains a subtree that does not depend on the
43/// value of the [ValueListenable], it's more efficient to build that subtree
44/// once instead of rebuilding it on every animation tick.
45///
46/// If you pass the pre-built subtree as the [child] parameter, the
47/// [ValueListenableBuilder] will pass it back to your [builder] function so
48/// that you can incorporate it into your build.
49///
50/// Using this pre-built child is entirely optional, but can improve
51/// performance significantly in some cases and is therefore a good practice.
52///
53/// {@tool dartpad}
54/// This sample shows how you could use a [ValueListenableBuilder] instead of
55/// setting state on the whole [Scaffold] in a counter app.
56///
57/// ** See code in examples/api/lib/widgets/value_listenable_builder/value_listenable_builder.0.dart **
58/// {@end-tool}
59///
60/// See also:
61///
62/// * [AnimatedBuilder], which also triggers rebuilds from a [Listenable]
63/// without passing back a specific value from a [ValueListenable].
64/// * [NotificationListener], which lets you rebuild based on [Notification]
65/// coming from its descendant widgets rather than a [ValueListenable] that
66/// you have a direct reference to.
67/// * [StreamBuilder], where a builder can depend on a [Stream] rather than
68/// a [ValueListenable] for more advanced use cases.
69/// * [TweenAnimationBuilder], which can animate values in a widget based on a
70/// [Tween].
71class ValueListenableBuilder<T> extends StatefulWidget {
72 /// Creates a [ValueListenableBuilder].
73 ///
74 /// The [child] is optional but is good practice to use if part of the widget
75 /// subtree does not depend on the value of the [valueListenable].
76 const ValueListenableBuilder({
77 super.key,
78 required this.valueListenable,
79 required this.builder,
80 this.child,
81 });
82
83 /// The [ValueListenable] whose value you depend on in order to build.
84 ///
85 /// This widget does not ensure that the [ValueListenable]'s value is not
86 /// null, therefore your [builder] may need to handle null values.
87 final ValueListenable<T> valueListenable;
88
89 /// A [ValueWidgetBuilder] which builds a widget depending on the
90 /// [valueListenable]'s value.
91 ///
92 /// Can incorporate a [valueListenable] value-independent widget subtree
93 /// from the [child] parameter into the returned widget tree.
94 final ValueWidgetBuilder<T> builder;
95
96 /// A [valueListenable]-independent widget which is passed back to the [builder].
97 ///
98 /// This argument is optional and can be null if the entire widget subtree the
99 /// [builder] builds depends on the value of the [valueListenable]. For
100 /// example, in the case where the [valueListenable] is a [String] and the
101 /// [builder] returns a [Text] widget with the current [String] value, there
102 /// would be no useful [child].
103 final Widget? child;
104
105 @override
106 State<StatefulWidget> createState() => _ValueListenableBuilderState<T>();
107}
108
109class _ValueListenableBuilderState<T> extends State<ValueListenableBuilder<T>> {
110 late T value;
111
112 @override
113 void initState() {
114 super.initState();
115 value = widget.valueListenable.value;
116 widget.valueListenable.addListener(_valueChanged);
117 }
118
119 @override
120 void didUpdateWidget(ValueListenableBuilder<T> oldWidget) {
121 super.didUpdateWidget(oldWidget);
122 if (oldWidget.valueListenable != widget.valueListenable) {
123 oldWidget.valueListenable.removeListener(_valueChanged);
124 value = widget.valueListenable.value;
125 widget.valueListenable.addListener(_valueChanged);
126 }
127 }
128
129 @override
130 void dispose() {
131 widget.valueListenable.removeListener(_valueChanged);
132 super.dispose();
133 }
134
135 void _valueChanged() {
136 setState(() {
137 value = widget.valueListenable.value;
138 });
139 }
140
141 @override
142 Widget build(BuildContext context) {
143 return widget.builder(context, value, widget.child);
144 }
145}
146

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com