美文网首页
2023-06-20 深入理解Flutter中的递归构建:Wid

2023-06-20 深入理解Flutter中的递归构建:Wid

作者: 我是小胡胡123 | 来源:发表于2023-06-19 11:15 被阅读0次

在Flutter中,Widget、Element、State和RenderObject是构建UI界面的核心概念。它们之间的关系是通过递归创建和管理的。

递归创建的过程如下:

  1. 创建根Widget:在Flutter应用程序中,首先创建一个根Widget,通常是一个MaterialApp或CupertinoApp。这个根Widget作为应用程序的入口点,它可以包含其他子Widget。
  2. 构建Widget树:根Widget通过调用其build()方法来构建自身及其子Widget。在build()方法中,可以创建和配置其他Widget,并返回一个新的Widget树。
  3. 创建Element:在根Widget的build()方法中,Flutter会为根Widget创建一个Element,这个Element作为根元素。然后,根Widget会递归地构建其子Widget,并为每个子Widget创建相应的Element。
  4. 更新和重建:如果在根Widget的状态发生更改时,例如用户交互触发了某个操作,Flutter会通知相关的Element更新。这会导致相应的Widget被重新构建,并生成新的Element。如果某个Widget的属性发生了变化,也会触发相应的Element更新和重建。
  5. 渲染树:Element构建完成后,Flutter会将所有Element组成的树转换为渲染树。渲染树是Flutter的内部表示,它描述了如何将Widget渲染为屏幕上的像素。
  6. 布局和绘制:渲染树中的每个节点都与一个RenderObject关联,它负责计算布局和绘制操作。RenderObject负责测量Widget的大小和位置,并将绘制命令发送给底层渲染引擎。

这样,通过递归地创建Widget、Element和RenderObject,Flutter可以构建出完整的UI界面,并在需要时更新和重建特定的部分。这种递归的方式确保了UI的一致性和高效性。

下面是一些相关的类的核心实现代码:

  1. Widget(部件):Widget是Flutter UI的构建块,它描述了用户界面的一部分。Widget是不可变的,意味着一旦创建,就不能更改它的属性。当需要更新UI时,创建一个新的Widget并替换旧的Widget。
@immutable
abstract class Widget extends DiagnosticableTree {
  @protected
  @factory
  Element createElement();

 
  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }

}

StatelessElement createElement() => StatelessElement(this);
StatefulElement createElement() => StatefulElement(this);
ParentDataElement<T> createElement() => ParentDataElement<T>(this);
InheritedElement createElement() => InheritedElement(this);
LeafRenderObjectElement createElement() => LeafRenderObjectElement(this);
SingleChildRenderObjectElement createElement() => SingleChildRenderObjectElement(this);
MultiChildRenderObjectElement createElement() => MultiChildRenderObjectElement(this);
Element createElement() => throw UnimplementedError();
 

  1. Element(元素):Element是Widget在UI树中的实例。每个Widget都对应一个Element,它负责管理Widget的生命周期、维护与其他元素的关系,并持有与该Widget实例相关的状态。

class StatefulElement extends ComponentElement {

  StatefulElement(StatefulWidget widget)


      : _state = widget.createState(),

        super(widget) {

    state._element = this;

    state._widget = widget;

  }

  @override
  Widget build() => state.build(this);



  State<StatefulWidget> get state => _state!;
  State<StatefulWidget>? _state;

  @override
  void reassemble() {
    if (_debugShouldReassemble(_debugReassembleConfig, _widget)) {
      state.reassemble();
    }
    super.reassemble();
  }

  @override
  void _firstBuild() {

    try {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      final Object? debugCheckForReturnedFuture = state.initState() as dynamic;


    } finally {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
    }

    state.didChangeDependencies();

    super._firstBuild();
  }

  @override
  void performRebuild() {
    if (_didChangeDependencies) {
      state.didChangeDependencies();
      _didChangeDependencies = false;
    }
    super.performRebuild();
  }

  @override
  void update(StatefulWidget newWidget) {
    super.update(newWidget);

    final StatefulWidget oldWidget = state._widget!; 


    _dirty = true;
    state._widget = widget as StatefulWidget;
    try {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic;
 
    } finally {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
    }
    rebuild();
  }

  @override
  void activate() {
    super.activate();
    state.activate();

    markNeedsBuild();
  }

  @override
  void deactivate() {
    state.deactivate();
    super.deactivate();
  }

  @override
  void unmount() {
    super.unmount();
    state.dispose();

    state._element = null;

    _state = null;
  }



  bool _didChangeDependencies = false;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _didChangeDependencies = true;
  }



}

ComponentElement实现如下:

abstract class ComponentElement extends Element {

  ComponentElement(Widget widget) : super(widget);

  Element? _child;

  bool _debugDoingBuild = false;
  @override
  bool get debugDoingBuild => _debugDoingBuild;

  @override
  void mount(Element? parent, Object? newSlot) {
    super.mount(parent, newSlot);
 
    _firstBuild();
 
  }

  void _firstBuild() {
 
    rebuild();  
  }

 
  @override
  @pragma('vm:notify-debugger-on-exception')
  void performRebuild() {
    assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true));
    Widget? built;
    try {
 
      _debugDoingBuild = true;
 
      built = build();
 
      _debugDoingBuild = false;
 
      debugWidgetBuilderValue(widget, built);
    } catch (e, stack) {
      _debugDoingBuild = false;
      built = ErrorWidget.builder(
        _debugReportException(
          ErrorDescription('building $this'),
          e,
          stack,
          informationCollector: () => <DiagnosticsNode>[
            if (kDebugMode)
              DiagnosticsDebugCreator(DebugCreator(this)),
          ],
        ),
      );
    } finally {
 
      _dirty = false;


    }
    try {
      _child = updateChild(_child, built, slot);
      assert(_child != null);
    } catch (e, stack) {
      built = ErrorWidget.builder(
        _debugReportException(
          ErrorDescription('building $this'),
          e,
          stack,
          informationCollector: () => <DiagnosticsNode>[
            if (kDebugMode)
              DiagnosticsDebugCreator(DebugCreator(this)),
          ],
        ),
      );
      _child = updateChild(null, built, slot);
    }
  }
 
  @protected
  Widget build();

  @override
  void visitChildren(ElementVisitor visitor) {
    if (_child != null)
      visitor(_child!);
  }

  @override
  void forgetChild(Element child) {
    assert(child == _child);
    _child = null;
    super.forgetChild(child);
  }
}

Element类核心实现如下:

abstract class Element extends DiagnosticableTree implements BuildContext {

  Element(Widget widget)
    : assert(widget != null),
      _widget = widget;

  Element? _parent;
  DebugReassembleConfig? _debugReassembleConfig;
  _NotificationNode? _notificationTree;

  @nonVirtual
  @override
  bool operator ==(Object other) => identical(this, other);


  Object? get slot => _slot;
  Object? _slot;

  int get depth {


    return _depth;
  }
  late int _depth;

  static int _sort(Element a, Element b) {
    if (a.depth < b.depth)
      return -1;
    if (b.depth < a.depth)
      return 1;
    if (b.dirty && !a.dirty)
      return -1;
    if (a.dirty && !b.dirty)
      return 1;
    return 0;
  }

  @override
  Widget get widget => _widget!;
  Widget? _widget;


  @override
  BuildOwner? get owner => _owner;
  BuildOwner? _owner;


  @mustCallSuper
  @protected
  void reassemble() {
    if (_debugShouldReassemble(_debugReassembleConfig, _widget)) {
      markNeedsBuild();
      _debugReassembleConfig = null;
    }
    visitChildren((Element child) {
      child._debugReassembleConfig = _debugReassembleConfig;
      child.reassemble();
    });
    _debugReassembleConfig = null;
  }


  RenderObject? get renderObject {
    RenderObject? result;
    void visit(Element element) {

      if (element._lifecycleState == _ElementLifecycle.defunct) {
        return;
      } else if (element is RenderObjectElement) {
        result = element.renderObject;
      } else {
        element.visitChildren(visit);
      }
    }
    visit(this);
    return result;
  }


  _ElementLifecycle _lifecycleState = _ElementLifecycle.initial;

  void visitChildren(ElementVisitor visitor) { }


  @override
  void visitChildElements(ElementVisitor visitor) {

    visitChildren(visitor);
  }

  @protected
  @pragma('vm:prefer-inline')
  Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
    if (newWidget == null) {
      if (child != null)
        deactivateChild(child);
      return null;
    }

    final Element newChild;
    if (child != null) {
      bool hasSameSuperclass = true;

 
      assert(() {
        final int oldElementClass = Element._debugConcreteSubtype(child);
        final int newWidgetClass = Widget._debugConcreteSubtype(newWidget);
        hasSameSuperclass = oldElementClass == newWidgetClass;
        return true;
      }()); 

      if (hasSameSuperclass && child.widget == newWidget) {

        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        newChild = child;
      } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
 

        child.update(newWidget);

        newChild = child;
      } else {
        deactivateChild(child);

        newChild = inflateWidget(newWidget, newSlot);
      }
    } else {

      newChild = inflateWidget(newWidget, newSlot);
    }


    return newChild;
  }


  @mustCallSuper
  void mount(Element? parent, Object? newSlot) {

    _parent = parent;
    _slot = newSlot;
    _lifecycleState = _ElementLifecycle.active;
    _depth = _parent != null ? _parent!.depth + 1 : 1;
    if (parent != null) {

      _owner = parent.owner;
    }

    final Key? key = widget.key;
    if (key is GlobalKey) {
      owner!._registerGlobalKey(key, this);
    }
    _updateInheritance();
    attachNotificationTree();
  }

  @mustCallSuper
  void update(covariant Widget newWidget) {

    _widget = newWidget;
  }

  @protected
  void updateSlotForChild(Element child, Object? newSlot) {


    void visit(Element element) {
      element._updateSlot(newSlot);
      if (element is! RenderObjectElement)
        element.visitChildren(visit);
    }
    visit(child);
  }

  void _updateSlot(Object? newSlot) {


    _slot = newSlot;
  }

  void _updateDepth(int parentDepth) {
    final int expectedDepth = parentDepth + 1;
    if (_depth < expectedDepth) {
      _depth = expectedDepth;
      visitChildren((Element child) {
        child._updateDepth(expectedDepth);
      });
    }
  }

  void detachRenderObject() {
    visitChildren((Element child) {
      child.detachRenderObject();
    });
    _slot = null;
  }

  void attachRenderObject(Object? newSlot) {

    visitChildren((Element child) {
      child.attachRenderObject(newSlot);
    });
    _slot = newSlot;
  }

  Element? _retakeInactiveElement(GlobalKey key, Widget newWidget) {

    final Element? element = key._currentElement;
    if (element == null)
      return null;
    if (!Widget.canUpdate(element.widget, newWidget))
      return null;


    final Element? parent = element._parent;
    if (parent != null) {


      parent.forgetChild(element);
      parent.deactivateChild(element);
    }

    owner!._inactiveElements.remove(element);
    return element;
  }


  @protected
  @pragma('vm:prefer-inline')
  Element inflateWidget(Widget newWidget, Object? newSlot) {



    try {
      final Key? key = newWidget.key;
      if (key is GlobalKey) {
        final Element? newChild = _retakeInactiveElement(key, newWidget);
        if (newChild != null) {


          newChild._activateWithParent(this, newSlot);
          final Element? updatedChild = updateChild(newChild, newWidget, newSlot);

          return updatedChild!;
        }
      }
      final Element newChild = newWidget.createElement();
 

      newChild.mount(this, newSlot);


      return newChild;
    } finally {
      if (isTimelineTracked)
        Timeline.finishSync();
    }
  }


  @protected
  void deactivateChild(Element child) {

    child._parent = null;
    child.detachRenderObject();
    owner!._inactiveElements.add(child); 

  }


  @protected
  @mustCallSuper
  void forgetChild(Element child) {



  }

  void _activateWithParent(Element parent, Object? newSlot) {

    _parent = parent;

    _updateDepth(_parent!.depth);
    _activateRecursively(this);
    attachRenderObject(newSlot);

  }

  static void _activateRecursively(Element element) {

    element.activate();

    element.visitChildren(_activateRecursively);
  }

  @mustCallSuper
  void activate() {

    final bool hadDependencies = (_dependencies != null && _dependencies!.isNotEmpty) || _hadUnsatisfiedDependencies;
    _lifecycleState = _ElementLifecycle.active;

    _dependencies?.clear();
    _hadUnsatisfiedDependencies = false;
    _updateInheritance();
    attachNotificationTree();
    if (_dirty)
      owner!.scheduleBuildFor(this);
    if (hadDependencies)
      didChangeDependencies();
  }

  @mustCallSuper
  void deactivate() {


    if (_dependencies != null && _dependencies!.isNotEmpty) {
      for (final InheritedElement dependency in _dependencies!)
        dependency._dependents.remove(this);

    }
    _inheritedWidgets = null;
    _lifecycleState = _ElementLifecycle.inactive;
  }

  @mustCallSuper
  void debugDeactivated() {

  }


  @mustCallSuper
  void unmount() {

    final Key? key = _widget?.key;
    if (key is GlobalKey) {
      owner!._unregisterGlobalKey(key, this);
    }

    _widget = null;
    _dependencies = null;
    _lifecycleState = _ElementLifecycle.defunct;
  }

  @override
  RenderObject? findRenderObject() {

    return renderObject;
  }

  @override
  Size? get size {

    final RenderObject? renderObject = findRenderObject();

    if (renderObject is RenderBox)
      return renderObject.size;
    return null;
  }

  Map<Type, InheritedElement>? _inheritedWidgets;
  Set<InheritedElement>? _dependencies;
  bool _hadUnsatisfiedDependencies = false;



  @override
  InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {

    _dependencies ??= HashSet<InheritedElement>();
    _dependencies!.add(ancestor);
    ancestor.updateDependencies(this, aspect);
    return ancestor.widget as InheritedWidget;
  }

  @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;
  }

  @override
  InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {

    final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
    return ancestor;
  }

  @protected
  void attachNotificationTree() {
    _notificationTree = _parent?._notificationTree;
  }

  void _updateInheritance() {

    _inheritedWidgets = _parent?._inheritedWidgets;
  }

  @override
  T? findAncestorWidgetOfExactType<T extends Widget>() {

    Element? ancestor = _parent;
    while (ancestor != null && ancestor.widget.runtimeType != T)
      ancestor = ancestor._parent;
    return ancestor?.widget as T?;
  }

  @override
  T? findAncestorStateOfType<T extends State<StatefulWidget>>() {

    Element? ancestor = _parent;
    while (ancestor != null) {
      if (ancestor is StatefulElement && ancestor.state is T)
        break;
      ancestor = ancestor._parent;
    }
    final StatefulElement? statefulAncestor = ancestor as StatefulElement?;
    return statefulAncestor?.state as T?;
  }

  @override
  T? findRootAncestorStateOfType<T extends State<StatefulWidget>>() {

    Element? ancestor = _parent;
    StatefulElement? statefulAncestor;
    while (ancestor != null) {
      if (ancestor is StatefulElement && ancestor.state is T)
        statefulAncestor = ancestor;
      ancestor = ancestor._parent;
    }
    return statefulAncestor?.state as T?;
  }

  @override
  T? findAncestorRenderObjectOfType<T extends RenderObject>() {

    Element? ancestor = _parent;
    while (ancestor != null) {
      if (ancestor is RenderObjectElement && ancestor.renderObject is T)
        return ancestor.renderObject as T;
      ancestor = ancestor._parent;
    }
    return null;
  }

  @override
  void visitAncestorElements(bool Function(Element element) visitor) {

    Element? ancestor = _parent;
    while (ancestor != null && visitor(ancestor))
      ancestor = ancestor._parent;
  }

  @mustCallSuper
  void didChangeDependencies() {


    markNeedsBuild();
  }




  @override
  void dispatchNotification(Notification notification) {
    _notificationTree?.dispatchNotification(notification);
  }


  bool get dirty => _dirty;
  bool _dirty = true;


  bool _inDirtyList = false;

  bool _debugBuiltOnce = false;



  void markNeedsBuild() {

    if (_lifecycleState != _ElementLifecycle.active)
      return;

    if (dirty)
      return;
    _dirty = true;
    owner!.scheduleBuildFor(this);
  }

  @pragma('vm:prefer-inline')
  void rebuild() {

    if (_lifecycleState != _ElementLifecycle.active || !_dirty)
      return;


    performRebuild();


  }

  @protected
  void performRebuild();
}
  1. State(状态):State是一个存储数据的对象,用于描述Widget的可变状态。当一个Widget需要跟踪一些数据并在运行时进行更改时,可以使用State。State可以与Widget关联,并在需要时更新Widget的显示。
abstract class State<T extends StatefulWidget> with Diagnosticable {

  T get widget => _widget!;
  T? _widget;

  _StateLifecycle _debugLifecycleState = _StateLifecycle.created;

  bool _debugTypesAreRight(Widget widget) => widget is T;


  BuildContext get context {
    return _element!;
  }

  StatefulElement? _element;

  bool get mounted => _element != null;


  @protected
  @mustCallSuper
  void initState() {
    assert(_debugLifecycleState == _StateLifecycle.created);
  }


  @mustCallSuper
  @protected
  void didUpdateWidget(covariant T oldWidget) { }


  @protected
  @mustCallSuper
  void reassemble() { } 


  @protected
  void setState(VoidCallback fn) {
    assert(fn != null);
     
    final Object? result = fn() as dynamic;
  
    _element!.markNeedsBuild();
  }


  @protected
  @mustCallSuper
  void deactivate() { } 

  @protected
  @mustCallSuper
  void activate() { }
 
  @protected
  @mustCallSuper
  void dispose() {


  } 

  @protected
  Widget build(BuildContext context);
 
  @protected
  @mustCallSuper
  void didChangeDependencies() { }

 
}

以下是一个简单的实例代码,演示了Flutter中递归创建Widget、Element、State和RenderObject的过程:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('递归创建示例'),
        ),
        body: MyWidget(),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            '计数器值:',
          ),
          Text(
            '$_counter',
            style: Theme.of(context).textTheme.headline4,
          ),
          RaisedButton(
            onPressed: _incrementCounter,
            child: Text('增加'),
          ),
          if (_counter > 5)
            MyWidget() // 递归创建MyWidget
        ],
      ),
    );
  }
}

相关文章

网友评论

      本文标题:2023-06-20 深入理解Flutter中的递归构建:Wid

      本文链接:https://www.haomeiwen.com/subject/frleydtx.html