Wechat official account: Android blog, with qr code at the end of the article
Personal website: chengang.plus
1, usage,
Usage Examples:
class InheritedData extends InheritedWidget {
final String data;
InheritedData({
this.data,
Widget child,
}) : super(child: child);
static InheritedData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<InheritedData>();
}
@override
bool updateShouldNotify(InheritedData old) => true;
}
class TestInheritedDataWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text(
"${InheritedData.of(context).data}",
style: TextStyle(fontSize: 18, color: Colors.pink), ), ); }}class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
var data = "you are beautiful";
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
child: Container(
color: Colors.cyan,
width: double.infinity,
child: InheritedData(
data: data,
child: TestInheritedDataWidget(),
),
),
onTap: _buttonClicked,
),
);
}
_buttonClicked() {
setState(() {
data = "in white"; }); }}Copy the code
2, ProxyWidget
InheritedWidget inherits from the ProxyWidget, and creates an InheritedElement object when createElement is called in the ProxyWidget.
2.1 InheritedElement
InheritedElement inherits from ProxyElement, InheritedElement inherits from ComponentElement, and ComponentElement inherits from Element.
InheritedElement defines a global Map object within the InheritedElement:
final Map<Element.Object> _dependents = HashMap<Element.Object> ();Copy the code
An _updateInheritance method is also defined. There is a definition in both Element and InheritedElement:
Element
void_updateInheritance() { _inheritedWidgets = _parent? ._inheritedWidgets; }Copy the code
Map
_inheritedWidgets defined in Element is a global variable.
InheritedElement
@override
void _updateInheritance() {
final Map<Type, InheritedElement> incomingWidgets = _parent? ._inheritedWidgets;if(incomingWidgets ! =null)
_inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets);
else
_inheritedWidgets = HashMap<Type, InheritedElement>();
_inheritedWidgets[widget.runtimeType] = this;
}
Copy the code
The primary logic of this method in InheritedElement is: If the existing Element exists, create a new one. Otherwise, add the existing Element to the _inheritedWidgets and add the current Element to the _inheritedWidgets.
The _updateInheritance method in Element is executed meaning that all the widgets corresponding to the Element hold an _inheritedWidgets, An InheritedWidget’s child can hold an InheritedElement directly via Element’s _updateInheritance method.
2.2 Save the InheritedElement node
So where does _updateInheritance get called?
Refer to the previous article on the Flutter Drawing Process series 2- Layout. In the Mount method of the Element class, the _updateInheritance method is called, which ends up here.
3. Update in ProxyElement
When the data in the InheritedWidget is updated by setState, the data-dependent Widget is updated as well.
3.1 ProxyElement Update method
@override
void update(ProxyWidget newWidget) {
final ProxyWidget oldWidget = widget;
super.update(newWidget);
updated(oldWidget);
_dirty = true;
rebuild();
}
Copy the code
To the updated method, in the InheritedElement method:
InheritedElement
@override
void updated(InheritedWidget oldWidget) {
if (widget.updateShouldNotify(oldWidget))
super.updated(oldWidget);
}
Copy the code
If updateShouldNotify returns true in our InheritedWidget, we execute the updated method on our InheritedElement:
@protected
void updated(covariant ProxyWidget oldWidget) {
notifyClients(oldWidget);
}
Copy the code
NotifyClients executes the notifyClients method on the InheritedElement in the subclass.
3.2 InheritedElement notifyClients method
@override
void notifyClients(InheritedWidget oldWidget) {
for (final Element dependent in_dependents.keys) { notifyDependent(oldWidget, dependent); }}Copy the code
This _dependents holds a node that relies on the InheritedWidget data.
3.3 _dependents Saves the Element that depends on the data
In the beginning of this chapter InheritedData provides a method of static, dependent child widgets (InheritedWidget) call dependOnInheritedWidgetOfExactType method. Implemented in the Element class, BuildContext defines:
Element implements the BuildContext interface
Element
@override
T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) {
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
if(ancestor ! =null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
Copy the code
Here we find the InheritedElement, and find the value (InheritedElement) using the _inheritedWidgets key (runtimeType). Next call the dependOnInheritedElement method:
Element
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Objectaspect }) { _dependencies ?? = HashSet<InheritedElement>(); _dependencies.add(ancestor); ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
Copy the code
In the Element class, determine if _dependencies is empty, create a HashSet, add the InheritedElement to it, and then execute the updateDependencies method. This refers to the Element of the InheritedWidget’s child Widget.
The updateDependencies are defined in the corresponding InheritedElement class:
InheritedElement
@override
void updateDependencies(Element dependent, Object aspect) {
final Set<T> dependencies = getDependencies(dependent) as Set<T>;
if(dependencies ! =null && dependencies.isEmpty)
return;
if (aspect == null) {
setDependencies(dependent, HashSet<T>());
} else{ setDependencies(dependent, (dependencies ?? HashSet<T>()).. add(aspectasT)); }}@protected
void setDependencies(Element dependent, Object value) {
_dependents[dependent] = value;
}
Copy the code
An _dependents Element is stored in the child Widget of the InheritedWidget.
3.4 Remind dependent Element updates
Return to the InheritedElement notifyClients method, which iterates over _dependents and executes notifyDependent:
InheritedElement
@protected
void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
dependent.didChangeDependencies();
}
@mustCallSuper
void didChangeDependencies() {
markNeedsBuild();
}
Copy the code
Go here to redraw widgets that rely on the InheritedWidget data.