Widget Element RenderObject关系

84 阅读2分钟

Widget 配置信息

@immutable
abstract class Widget extends DiagnosticableTree {
  /// Initializes [key] for subclasses.
  const Widget({ this.key });

  final Key? key;

 
  @override
  String toStringShort() {
    final String type = objectRuntimeType(this, 'Widget');
    return key == null ? type : '$type-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  @override
  @nonVirtual
  bool operator ==(Object other) => super == other;

  @override
  @nonVirtual
  int get hashCode => super.hashCode;

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


  static int _debugConcreteSubtype(Widget widget) {
    return widget is StatefulWidget ? 1 :
           widget is StatelessWidget ? 2 :
           0;
    }
}

abstract class RenderObjectWidget extends Widget {
 
  const RenderObjectWidget({ Key? key }) : super(key: key);

  @override
  @factory
  RenderObjectElement createElement();

  @protected
  @factory
  RenderObject createRenderObject(BuildContext context);

  @protected
  void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }

  @protected
  void didUnmountRenderObject(covariant RenderObject renderObject) { }
}

Widget子类
  1. RenderObjectWidget
  2. SingleChildRenderObjectWidget
  3. MultiChildRenderObjectWidget
  4. StatefulWidget
  5. StatelessWidget
  6. SingleChildWidget
  7. PreferredSizeWidget
  8. CustomMultiChildLayout
  9. CustomSingleChildLayout

RenderObject 最后干活的人


class ShadowBox extends SingleChildRenderObjectWidget {
  final Widget? child;
  final double? distance;

  ShadowBox({this.child, this.distance = 20}) : super(child: child);

  //运行时类型和key一样的话不会重新创建RenderObject
  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderShadowBox2(distance);
  }

  //因为类型没有变RenderBox就会捡回去继续使用,但是你可以修改RenderBox的属性
  @override
  void updateRenderObject(
      BuildContext context, covariant RenderShadowBox2 renderObject) {
    renderObject.distance = distance;
  }
}

///继承功能相似的RenderBox
class RenderShadowBox extends RenderBox with RenderObjectWithChildMixin {
  double? distance;

  RenderShadowBox(this.distance);

  @override
  void performLayout() {
    //父组件使用子size 因为有些 父组件不需要使用子组件的size
    child?.layout(constraints, parentUsesSize: true);
    //child?.layout(BoxConstraints.tight(Size(50,50)));
    //size = Size(300,300);
    size = (child as RenderBox).size;
  }

  //无中生有
  @override
  void paint(PaintingContext context, Offset offset) {
    context.paintChild(child!, offset);
    var canvas = context.canvas;
    // canvas.drawCircle(offset+Offset(50,50), 50, Paint()..color=Colors.white);
    //建立新的图层
    context.pushOpacity(offset, 127, (context, offset) {
      context.paintChild(
          child!, offset + Offset(distance ?? 20, distance ?? 20));
    });
  }
}

class RenderShadowBox2 extends RenderProxyBox with DebugOverflowIndicatorMixin {
  double? distance;

  RenderShadowBox2(this.distance);

  //无中生有
  @override
  void paint(PaintingContext context, Offset offset) {
    context.paintChild(child!, offset);
    context.pushOpacity(offset, 127, (context, offset) {
      context.paintChild(
          child!, offset + Offset(distance ?? 20, distance ?? 20));
    });
    //开发者 自己画的
    paintOverflowIndicator(
      context,
      offset,
      //能画的区域
      //Rect.fromLTWH(0, 0, size.width, size.height),
      Offset.zero & size,
      //子组件要画的区域
      //Rect.fromLTWH(0, 0, 320, 300),
      Offset.zero & child!.size,
    );
  }
}


    ///使用MyMultiChildLayoutDelegate

    CustomMultiChildLayout(
        delegate: MyMultiChildLayoutDelegate(),
        children: [
          LayoutId(
            child: Container(
              color: Colors.red,
            ),
            id: "underline",
          ),
          LayoutId(
            child: Text("WSBT"),
            id: "text",
          ),
        ],
      )


class MyMultiChildLayoutDelegate extends MultiChildLayoutDelegate {
  late Size size1,size2,size3,size4,size5;
  double top = 100;

  @override
  Size getSize(BoxConstraints constraints) {
    // TODO: implement getSize
    return Size(400,400);
  }

  @override
  void performLayout(Size size) {
    if (hasChild(1)) {
       size1 = layoutChild(
          1,
          BoxConstraints(
              minHeight: 50, maxHeight: 50, minWidth: 50, maxWidth: 50));
      positionChild(1, Offset(0, top));
    }

    if (hasChild(2)) {
       size2 = layoutChild(
          2,
          BoxConstraints.tight(Size(80,80)));
      positionChild(2, Offset(size1.width, top+size1.height));
    }
    if (hasChild(3)) {
      size3 = layoutChild(
          3,
          BoxConstraints.loose(size));
      positionChild(3, Offset(size1.width+size2.width, top+size1.height+size2.height));
    }
    if (hasChild(4)) {
      size4 = layoutChild(
          4,
          BoxConstraints.loose(size));
      positionChild(4, Offset(0,0));
    }

    if (hasChild(5)) {
      size5 = layoutChild(
          5,
          BoxConstraints.tight(
            Size(
              size4.width, 5)
          ));
      positionChild(5, Offset(0,size4.height));
    }
  }

  @override
  bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) {
    return true;
  }
}


    //使用
	 body: Container(
        color: Colors.blue,
        child: CustomMultiChildLayout(
          delegate: MyMultiChildLayoutDelegate(),
          children: [
            LayoutId(id: 1, child: FlutterLogo()),
            LayoutId(id: 2, child: FlutterLogo()),
            LayoutId(id: 3, child: FlutterLogo(size: 100,)),
            LayoutId(id: 4, child: Text("hello")),
            LayoutId(id: 5, child: Container(color: Colors.red)),
          ],
        ),
      ),


另外一个干活的
class MyCustomPainter extends CustomPainter {
  final List<Snowflake> _datas;
  final whitePaint = Paint()..color = Colors.white;

  MyCustomPainter(this._datas);

  @override
  void paint(Canvas canvas, Size size) {
    //loge(size);
    //canvas.drawCircle(Offset(size.width/2, size.height/2), 20, Paint());
    canvas.drawCircle(size.center(Offset(0, 100)), 60, whitePaint);
    canvas.drawOval(
        Rect.fromCenter(
            center: size.center(Offset(0, 280)), width: 200, height: 250),
        whitePaint);

    _datas.forEach((snowflake) {
      canvas.drawCircle(
          Offset(snowflake.x, snowflake.y), snowflake.radius, whitePaint);
    });
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
RenderObject

RenderBox

Element 事比较多

  1. mount->widget.createRenderObject(this)
  2. update->widget.updateRenderObject(this, renderObject)
  3. updateChild->通过widget更改子
Element子类
  1. ComponentElement

1.1 不会直接创建RenderObject,但是会创建其他的element,让他们创建RenderObject

1.2 StatelessElement StatefulElement ProxyElement

  1. RenderObjectElement

2.1 会直接创建ReaderObject