SingleChildRenderObjectWidget和LeafRenderObjectWidget,ContainerLayer说明和示例

1,635 阅读2分钟

SingleChildRenderObjectWidget使用和说明:

  1. 可以放入一个child节点
  2. Widget在初次attach时createRenderObject
  3. Widget在更新时,触发自己的重建和RenderObject的update操作,Widget需要把自身的更改准确的传递给RenderObject.而RenderObject需要吸收变更内容,根据情况markNeedsPaint
  4. child主要是element操作(The child is optional.)
  5. mount和update的时候,element都会带一带child这个小老弟.同时要求本Widget的RenderObject需要With RenderObjectWithChildMixin(例如RenderProxyBox),让child有地方呆.
class MyRenderPhysicalShapeDemo extends StatefulWidget {
  @override
  MyRenderPhysicalShapeState createState() {
    return MyRenderPhysicalShapeState();
  }
}

class MyRenderPhysicalShapeState extends State<MyRenderPhysicalShapeDemo> {
  double _elevation = 0.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('MyRenderPhysicalShapeDemo')),
        body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Slider(
                value: _elevation,
                onChanged: (value) => setState(() => _elevation = value),
              ),
              MyPhysicalShape(
                elevation: _elevation,
                child: Container(
                  width: 50,
                  height: 50,
                ),
              )
            ]));
  }
}

class MyPhysicalShape extends SingleChildRenderObjectWidget {
  final _elevation;

  MyPhysicalShape({double elevation, Widget child})
      : this._elevation = elevation,
        super(child: child);
  @override
  RenderPhysicalShape createRenderObject(BuildContext context) {
    return RenderPhysicalShape(
      clipBehavior: Clip.none,
      color: Color(0x61000000),
      clipper: ShapeBorderClipper(
        shape: CircleBorder(),
        textDirection: Directionality.of(context),
      ),
      shadowColor: Colors.black,
      elevation: _elevation,
    );
  }

  @override
  void updateRenderObject(BuildContext context, RenderPhysicalShape renderObject) {
    renderObject
      ..elevation = _elevation;
  }
}

LeafRenderObjectWidget使用和说明: 这里比这SingleChildRenderObjectWidget少了child,其余相同.

class MyRenderBoxWidget extends LeafRenderObjectWidget {
  final _elevation;

  MyRenderBoxWidget({double elevation})
      : this._elevation = elevation,
        super();

  @override
  MyRenderBox createRenderObject(BuildContext context) {
    return MyRenderBox(
      elevation: _elevation,
    );
  }
  @override
  void updateRenderObject(BuildContext context, MyRenderBox renderObject) {
    renderObject
      ..elevation = _elevation;
  }
}

class MyRenderBox extends RenderBox {
  MyRenderBox({
    double elevation = 0.0,
  }) : _elevation = elevation,
        super();

  @override
  PhysicalModelLayer get layer => super.layer;

  @override
  Path get _defaultClip => Path()..addRect(Offset.zero & size);

  @override
  void performLayout() {
    size = Size(100, 100);
  }

  @override
  void paint(PaintingContext context, Offset offset) {
      final Rect offsetBounds = offset & size;
      final Path offsetPath = _defaultClip.shift(offset);
      layer ??= PhysicalModelLayer();
      layer
        ..clipPath = offsetPath
        ..clipBehavior = Clip.none
        ..elevation = elevation
        ..color = Color(0x61000000)
        ..shadowColor = Colors.black;
      context.pushLayer(layer, super.paint, offset, childPaintBounds: offsetBounds);
  }

  double get elevation => _elevation;
  double _elevation;
  set elevation(double value) {
    if (elevation == value)
      return;
    _elevation = value;
    markNeedsPaint();
  }

}


// addToScene 将内容传递给ui.SceneBuilder
class MyLayer extends ContainerLayer{

  Path get clipPath => _clipPath;
  Path _clipPath;
  set clipPath(Path value) {
    if (value != _clipPath) {
      _clipPath = value;
      markNeedsAddToScene();
    }
  }
  /// {@macro flutter.widgets.Clip}
  Clip get clipBehavior => _clipBehavior;
  Clip _clipBehavior;
  set clipBehavior(Clip value) {
    assert(value != null);
    if (value != _clipBehavior) {
      _clipBehavior = value;
      markNeedsAddToScene();
    }
  }
  double get elevation => _elevation;
  double _elevation;
  set elevation(double value) {
    if (value != _elevation) {
      _elevation = value;
      markNeedsAddToScene();
    }
  }

  Color get color => _color;
  Color _color;
  set color(Color value) {
    if (value != _color) {
      _color = value;
      markNeedsAddToScene();
    }
  }

  /// The shadow color.
  Color get shadowColor => _shadowColor;
  Color _shadowColor;
  set shadowColor(Color value) {
    if (value != _shadowColor) {
      _shadowColor = value;
      markNeedsAddToScene();
    }
  }
  @protected
  ui.EngineLayer get engineLayer => _engineLayer;

  @protected
  set engineLayer(ui.EngineLayer value) {
    super.engineLayer = value;
    _engineLayer = value;
    if (!alwaysNeedsAddToScene) {
      if (parent != null && !parent.alwaysNeedsAddToScene) {
        parent.markNeedsAddToScene();
      }
    }
  }
  ui.EngineLayer _engineLayer;
  @override
  void addToScene(ui.SceneBuilder builder, [Offset layerOffset = Offset.zero]) {
    engineLayer = builder.pushPhysicalShape(
      path: layerOffset == Offset.zero ? clipPath : clipPath.shift(layerOffset),
      elevation: elevation,
      color: color,
      shadowColor: shadowColor,
      clipBehavior: clipBehavior,
      oldLayer: _engineLayer,
    );
  }

  // 点击事件
  @override
  S find<S>(Offset regionOffset) {

    return null;
  }
  // 点击事件
  @override
  Iterable<S> findAll<S>(Offset regionOffset) {

    return null;
  }

}