@@ -1870,6 +1870,19 @@ abstract class BuildContext {
1870
1870
/// render object is usually short.
1871
1871
Size get size;
1872
1872
1873
+ /// Registers this build context with [ancestor] such that when
1874
+ /// [ancestor] 's widget changes this build context is rebuilt.
1875
+ ///
1876
+ /// Returns `ancestor.widget` .
1877
+ ///
1878
+ /// This method is rarely called directly. Most applications should use
1879
+ /// [inheritFromWidgetOfExactType] , which calls this method after finding
1880
+ /// the appropriate [InheritedElement] ancestor.
1881
+ ///
1882
+ /// All of the qualifications about when [inheritFromWidgetOfExactType] can
1883
+ /// be called apply to this method as well.
1884
+ InheritedWidget inheritFromElement (InheritedElement ancestor, { Object aspect });
1885
+
1873
1886
/// Obtains the nearest widget of the given type, which must be the type of a
1874
1887
/// concrete [InheritedWidget] subclass, and registers this build context with
1875
1888
/// that widget such that when that widget changes (or a new widget of that
@@ -1879,7 +1892,7 @@ abstract class BuildContext {
1879
1892
/// This is typically called implicitly from `of()` static methods, e.g.
1880
1893
/// [Theme.of] .
1881
1894
///
1882
- /// This should not be called from widget constructors or from
1895
+ /// This method should not be called from widget constructors or from
1883
1896
/// [State.initState] methods, because those methods would not get called
1884
1897
/// again if the inherited value were to change. To ensure that the widget
1885
1898
/// correctly updates itself when the inherited value changes, only call this
@@ -1892,9 +1905,9 @@ abstract class BuildContext {
1892
1905
/// It is safe to use this method from [State.deactivate] , which is called
1893
1906
/// whenever the widget is removed from the tree.
1894
1907
///
1895
- /// It is also possible to call this from interaction event handlers (e.g.
1896
- /// gesture callbacks) or timers, to obtain a value once, if that value is not
1897
- /// going to be cached and reused later.
1908
+ /// It is also possible to call this method from interaction event handlers
1909
+ /// (e.g. gesture callbacks) or timers, to obtain a value once, if that value
1910
+ /// is not going to be cached and reused later.
1898
1911
///
1899
1912
/// Calling this method is O(1) with a small constant factor, but will lead to
1900
1913
/// the widget being rebuilt more often.
@@ -1904,7 +1917,12 @@ abstract class BuildContext {
1904
1917
/// called, whenever changes occur relating to that widget until the next time
1905
1918
/// the widget or one of its ancestors is moved (for example, because an
1906
1919
/// ancestor is added or removed).
1907
- InheritedWidget inheritFromWidgetOfExactType (Type targetType);
1920
+ ///
1921
+ /// The [aspect] parameter is only used when [targetType] is an
1922
+ /// [InheritedWidget] subclasses that supports partial updates, like
1923
+ /// [InheritedModel] . It specifies what "aspect" of the inherited
1924
+ /// widget this context depends on.
1925
+ InheritedWidget inheritFromWidgetOfExactType (Type targetType, { Object aspect });
1908
1926
1909
1927
/// Obtains the element corresponding to the nearest widget of the given type,
1910
1928
/// which must be the type of a concrete [InheritedWidget] subclass.
@@ -3226,15 +3244,21 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
3226
3244
}
3227
3245
3228
3246
@override
3229
- InheritedWidget inheritFromWidgetOfExactType (Type targetType) {
3247
+ InheritedWidget inheritFromElement (InheritedElement ancestor, { Object aspect }) {
3248
+ assert (ancestor != null );
3249
+ _dependencies ?? = new HashSet <InheritedElement >();
3250
+ _dependencies.add (ancestor);
3251
+ ancestor.updateDependencies (this , aspect);
3252
+ return ancestor.widget;
3253
+ }
3254
+
3255
+ @override
3256
+ InheritedWidget inheritFromWidgetOfExactType (Type targetType, { Object aspect }) {
3230
3257
assert (_debugCheckStateIsActiveForAncestorLookup ());
3231
3258
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
3232
3259
if (ancestor != null ) {
3233
3260
assert (ancestor is InheritedElement );
3234
- _dependencies ?? = new HashSet <InheritedElement >();
3235
- _dependencies.add (ancestor);
3236
- ancestor._dependents.add (this );
3237
- return ancestor.widget;
3261
+ return inheritFromElement (ancestor, aspect: aspect);
3238
3262
}
3239
3263
_hadUnsatisfiedDependencies = true ;
3240
3264
return null ;
@@ -3845,11 +3869,13 @@ class StatefulElement extends ComponentElement {
3845
3869
}
3846
3870
3847
3871
@override
3848
- InheritedWidget inheritFromWidgetOfExactType (Type targetType) {
3872
+ InheritedWidget inheritFromElement (Element ancestor, { Object aspect }) {
3873
+ assert (ancestor != null );
3849
3874
assert (() {
3875
+ final Type targetType = ancestor.widget.runtimeType;
3850
3876
if (state._debugLifecycleState == _StateLifecycle .created) {
3851
3877
throw new FlutterError (
3852
- 'inheritFromWidgetOfExactType($targetType ) was called before ${_state .runtimeType }.initState() completed.\n '
3878
+ 'inheritFromWidgetOfExactType($targetType ) or inheritFromElement() was called before ${_state .runtimeType }.initState() completed.\n '
3853
3879
'When an inherited widget changes, for example if the value of Theme.of() changes, '
3854
3880
'its dependent widgets are rebuilt. If the dependent widget\' s reference to '
3855
3881
'the inherited widget is in a constructor or an initState() method, '
@@ -3862,7 +3888,7 @@ class StatefulElement extends ComponentElement {
3862
3888
}
3863
3889
if (state._debugLifecycleState == _StateLifecycle .defunct) {
3864
3890
throw new FlutterError (
3865
- 'inheritFromWidgetOfExactType($targetType ) called after dispose(): $this \n '
3891
+ 'inheritFromWidgetOfExactType($targetType ) or inheritFromElement() was called after dispose(): $this \n '
3866
3892
'This error happens if you call inheritFromWidgetOfExactType() on the '
3867
3893
'BuildContext for a widget that no longer appears in the widget tree '
3868
3894
'(e.g., whose parent widget no longer includes the widget in its '
@@ -3882,7 +3908,7 @@ class StatefulElement extends ComponentElement {
3882
3908
}
3883
3909
return true ;
3884
3910
}());
3885
- return super .inheritFromWidgetOfExactType (targetType );
3911
+ return super .inheritFromElement (ancestor, aspect : aspect );
3886
3912
}
3887
3913
3888
3914
@override
@@ -4032,7 +4058,7 @@ class InheritedElement extends ProxyElement {
4032
4058
@override
4033
4059
InheritedWidget get widget => super .widget;
4034
4060
4035
- final Set <Element > _dependents = new HashSet <Element >();
4061
+ final Map <Element , Object > _dependents = new HashMap <Element , Object >();
4036
4062
4037
4063
@override
4038
4064
void _updateInheritance () {
@@ -4054,6 +4080,110 @@ class InheritedElement extends ProxyElement {
4054
4080
super .debugDeactivated ();
4055
4081
}
4056
4082
4083
+ /// Returns the dependencies value recorded for [dependent]
4084
+ /// with [setDependencies] .
4085
+ ///
4086
+ /// Each dependent element is mapped to a single object value
4087
+ /// which represents how the element depends on this
4088
+ /// [InheritedElement] . This value is null by default and by default
4089
+ /// dependent elements are rebuilt unconditionally.
4090
+ ///
4091
+ /// Subclasses can manage these values with [updateDependencies]
4092
+ /// so that they can selectively rebuild dependents in
4093
+ /// [notifyDependents] .
4094
+ ///
4095
+ /// This method is typically only called in overrides of [updateDependencies] .
4096
+ ///
4097
+ /// See also:
4098
+ ///
4099
+ /// * [updateDependencies] , which is called each time a dependency is
4100
+ /// created with [inheritFromWidgetOfExactType].
4101
+ /// * [setDependencies] , which sets dependencies value for a dependent
4102
+ /// element.
4103
+ /// * [notifyDependent] , which can be overridden to use a dependent's
4104
+ /// dependencies value to decide if the dependent needs to be rebuilt.
4105
+ /// * [InheritedModel] , which is an example of a class that uses this method
4106
+ /// to manage dependency values.
4107
+ @protected
4108
+ Object getDependencies (Element dependent) {
4109
+ return _dependents[dependent];
4110
+ }
4111
+
4112
+ /// Sets the value returned by [getDependencies] value for [dependent] .
4113
+ ///
4114
+ /// Each dependent element is mapped to a single object value
4115
+ /// which represents how the element depends on this
4116
+ /// [InheritedElement] . The [updateDependencies] method sets this value to
4117
+ /// null by default so that dependent elements are rebuilt unconditionally.
4118
+ ///
4119
+ /// Subclasses can manage these values with [updateDependencies]
4120
+ /// so that they can selectively rebuild dependents in [notifyDependents] .
4121
+ ///
4122
+ /// This method is typically only called in overrides of [updateDependencies] .
4123
+ ///
4124
+ /// See also:
4125
+ ///
4126
+ /// * [updateDependencies] , which is called each time a dependency is
4127
+ /// created with [inheritFromWidgetOfExactType].
4128
+ /// * [getDependencies] , which returns the current value for a dependent
4129
+ /// element.
4130
+ /// * [notifyDependent] , which can be overridden to use a dependent's
4131
+ /// [getDependencies] value to decide if the dependent needs to be rebuilt.
4132
+ /// * [InheritedModel] , which is an example of a class that uses this method
4133
+ /// to manage dependency values.
4134
+ @protected
4135
+ void setDependencies (Element dependent, Object value) {
4136
+ _dependents[dependent] = value;
4137
+ }
4138
+
4139
+ /// Called by [inheritFromWidgetOfExactType] when a new [dependent] is added.
4140
+ ///
4141
+ /// Each dependent element can be mapped to a single object value with
4142
+ /// [setDependencies] . This method can lookup the existing dependencies with
4143
+ /// [getDependencies] .
4144
+ ///
4145
+ /// By default this method sets the inherited dependencies for [dependent]
4146
+ /// to null. This only serves to record an unconditional dependency on
4147
+ /// [dependent] .
4148
+ ///
4149
+ /// Subclasses can manage their own dependencies values so that they
4150
+ /// can selectively rebuild dependents in [notifyDependents] .
4151
+ ///
4152
+ /// See also:
4153
+ ///
4154
+ /// * [getDependencies] , which returns the current value for a dependent
4155
+ /// element.
4156
+ /// * [setDependencies] , which sets the value for a dependent element.
4157
+ /// * [notifyDependent] , which can be overridden to use a dependent's
4158
+ /// dependencies value to decide if the dependent needs to be rebuilt.
4159
+ /// * [InheritedModel] , which is an example of a class that uses this method
4160
+ /// to manage dependency values.
4161
+ @protected
4162
+ void updateDependencies (Element dependent, Object aspect) {
4163
+ setDependencies (dependent, null );
4164
+ }
4165
+
4166
+ /// Called by [notifyClients] for each dependent.
4167
+ ///
4168
+ /// Calls `dependent.didChangeDependencies()` by default.
4169
+ ///
4170
+ /// Subclasses can override this method to selectively call
4171
+ /// [didChangeDependencies] based on the value of [getDependencies] .
4172
+ ///
4173
+ /// See also:
4174
+ ///
4175
+ /// * [updateDependencies] , which is called each time a dependency is
4176
+ /// created with [inheritFromWidgetOfExactType].
4177
+ /// * [getDependencies] , which returns the current value for a dependent
4178
+ /// element.
4179
+ /// * [setDependencies] , which sets the value for a dependent element.
4180
+ /// * [InheritedModel] , which is an example of a class that uses this method
4181
+ /// to manage dependency values.
4182
+ @protected
4183
+ void notifyDependent (covariant InheritedWidget oldWidget, Element dependent) {
4184
+ dependent.didChangeDependencies ();
4185
+ }
4186
+
4057
4187
/// Calls [Element.didChangeDependencies] of all dependent elements, if
4058
4188
/// [InheritedWidget.updateShouldNotify] returns true.
4059
4189
///
@@ -4070,7 +4200,7 @@ class InheritedElement extends ProxyElement {
4070
4200
if (! widget.updateShouldNotify (oldWidget))
4071
4201
return ;
4072
4202
assert (_debugCheckOwnerBuildTargetExists ('notifyClients' ));
4073
- for (Element dependent in _dependents) {
4203
+ for (Element dependent in _dependents.keys ) {
4074
4204
assert (() {
4075
4205
// check that it really is our descendant
4076
4206
Element ancestor = dependent._parent;
@@ -4080,7 +4210,7 @@ class InheritedElement extends ProxyElement {
4080
4210
}());
4081
4211
// check that it really depends on us
4082
4212
assert (dependent._dependencies.contains (this ));
4083
- dependent. didChangeDependencies ( );
4213
+ notifyDependent (oldWidget, dependent );
4084
4214
}
4085
4215
}
4086
4216
}
0 commit comments