首页 > 其他分享 >flutter —— RenderObject 的布局原理

flutter —— RenderObject 的布局原理

时间:2023-02-03 14:22:13浏览次数:68  
标签:RenderObject void 节点 extends override 原理 flutter super 重绘

RenderObject 的布局原理

① relayoutBoundary

重布局边界。该参数用于表示子节点布局变化是否影响父节点,如果为true,当子节点布局发生变化时父节点都会标记为需要重新布局,如果为false,则子节点布局发生变化后不会影响父节点。

void layout(Constraints constraints, { bool parentUsesSize = false }) {
   ...
   RenderObject relayoutBoundary; 
    if (!parentUsesSize || sizedByParent || constraints.isTight 
    	|| parent is! RenderObject) {
      relayoutBoundary = this;
    } else {
      final RenderObject parent = this.parent;
      relayoutBoundary = parent._relayoutBoundary;
    }
    ...
    if (sizedByParent) {
        performResize();
    }
    performLayout();
    ...
}

② performResize()

当 sizedByParent 为true 时,节点的大小仅通过 parent 传给它的 constraints 就可以确定了,即该节点的大小与它自身的属性和其子节点无关,此时其大小在 performResize() 中就确定了,performLayout() 不能用于改变组件大小。

class _RenderCircleBox extends RenderProxyBox {
  _RenderCircleBox();

  @override
  bool get sizedByParent => true;

  @override
  void performResize() {
    super.performResize();
    size = constraints.constrain(Size(constraints.maxWidth, 100));
  }

  @override
  void performLayout() {
    
  }

}

③ RepaintBoundary

独立绘制边界

1)如果没有该边界,别的组件重绘(如执行动画、CustomPainter 中 shouldRepaint 返回 true 等)会导致整个 Layer 重绘,继而导致包含在同一个 Layer 的当前组件重绘;反之,当前组件重绘也会影响别的组件(如果有边界,在绘制时仅会重绘自身而无需重绘它的 parent)。

示例:共享 Layer 导致的重绘

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    print('home dd');
    return Scaffold(
      body: Center(
          child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          CircleBox(),
          SquareBox(),
        ],
      )),
    );
  }
}

class CircleBox extends LeafRenderObjectWidget {
  const CircleBox({super.key});

  @override
  RenderObject createRenderObject(BuildContext context) {
    return _RenderCircleBox();
  }
}

class _RenderCircleBox extends RenderProxyBox {
  _RenderCircleBox();

  @override
  void performLayout() {
    super.performLayout();
    size = constraints.constrain(Size(100, 100));
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    print('circle painting...');
    context.canvas.drawCircle(offset.translate(50, 50), size.width / 2, Paint());
  }

  @override
  bool hitTest(BoxHitTestResult result, {required Offset position}) {
    return false;
  }

// 当 isRepaintBoundary 返回 false,SquareBox 点击时触发的动画导致 Layer 重绘,继而导致 CircleBox 重绘。
  @override
  bool get isRepaintBoundary => false;
}

class SquareBox extends StatefulWidget {
  const SquareBox({Key? key}) : super(key: key);

  @override
  State<SquareBox> createState() => _SquareBoxState();
}

class _SquareBoxState extends State<SquareBox> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    print('square build');
    return GestureDetector(
      behavior: HitTestBehavior.translucent,
      onTap: () {
        _controller.forward(from: 0);
      },
      child: RotationTransition(
        turns: Tween(begin: 0.0, end: 0.5).animate(_controller),
        child: Container(
          color: Colors.green,
          height: 200,
          width: 200,
        ),
      ),
    );
  }
}

注:
setState 执行的是 markNeedsBuild,会导致 widget 重建(调用 Element 的 rebuild 方法 ),但不一定会导致节点重绘(调用 RenderObject 的 markNeedsPaint 方法)。参考 setState 流程

有几种情况会导致组件重绘:

  1. 当 widget 重建导致布局信息变化影响子节点布局时,会导致子节点重绘
  2. 重建时子节点执行 updateRenderObject 方法,如果 renderObject 属性变化,则通常会调用 markNeedsPaint() 重绘
  3. 对于子节点是 CustomPaint,执行 updateRenderObject 方法会调用 set painter 属性方法,该方法执行时判断 CustomPainter 组件的 shouldRepaint 方法是否返回 true,若返回 true 则会调用 markNeedsPaint() 重绘。

2)设置边界的情况下,自定义 RenderBox 组件,默认布局,在绘制时 offset 是相对当前 Layer(可以理解为画布)进行偏移。

class RenderRepaintBoundary extends RenderProxyBox {
  /// Creates a repaint boundary around [child].
  RenderRepaintBoundary({ RenderBox child }) : super(child);

  @override
  void paint(PaintingContext context, Offset offset) {
    // 参数列表中的 offset 是相对当前 layer 的偏移量。同时 drawCircle 的起始偏移也是相对于当前 layer 进行偏移。
    // 如果 isRepaintBoundary 返回 true,节点自身就是 layer,那么参数列表中的 offset 等于零,
    // drawCircle 则是相当于当前节点自身位置进行绘制。
    context.canvas.drawCircle(Offset(10, 10), size.width / 2, Paint());
  }

// 也可直接用 RepaintBoundary 对当前组件进行包装
  @override
  bool get isRepaintBoundary => true;
}

标签:RenderObject,void,节点,extends,override,原理,flutter,super,重绘
From: https://www.cnblogs.com/lemos/p/17089087.html

相关文章

  • 爬虫基本原理
    爬虫概述获取网页并提取和保存信息的自动化程序1、获取网页urllib、requests等库向网站的服务器发送一个请求,服务器返回网页源码2、提取信息分析源代码,从中提取我们......
  • kotlin的拓展函数和原理
    kotlin的拓展函数和原理问题背景kotlin的使用过程中有个拓展函数的概念,这个概念在java中是没有的,那么问题来了,kotlin中拓展函数是什么呢?拓展函数的概念:不改变原有类的情......
  • Flutter Completer 的妙用
    适用场景:1.例如在app启动的时候,需要初始化数据(例如从服务端拉取数据),初始化的时间比较久,或者受限于网络,时间不可控,后面用户点击了某个操作,这个操作依赖于初始化,就需要等待初......
  • Spark核心原理
     1.概要介绍1.1master节点和work节点master和worker是物理节点 spark集群有一个master节点和多个worker节点。Standalone模式下可以通过zookeeper......
  • 686~687 Servlet执行原理 AND Servlet生命周期方法
    Servlet执行原理1.当服务器接受到客户端的请求后,会解析请求URL路径,获取访问的Servlet的资源路径2.查找web.xml文件,是否有对应的<url-pattern>标签体内容3.......
  • 《RPC实战与核心原理》学习笔记Day16
    23|如何在没有接口的情况下进行RPC调用?我们什么情况下需要在没有接口时进行RPC调用?列举2个典型场景:我们搭建一个测试平台,允许各个业务方在测试凭条上通过输入接口、......
  • Request-原理和Request继承体系
    Request-原理Request继承体系request对象继承体系结构:ServletRequest--接口|继承HttpServletRequest--接口......
  • WGCLOUD的原理和使用分享 - 实时监测服务器CPU温度
    WGCLOUD具备自动监测主机CPU温度的能力,不用配置,只要启动被控端agent就行了,它会自动采集CPU温度指标数据,如下图不过测试中,发现貌似虚拟机采集不到CPU温度,实体机是可以采集CPU......
  • Flutter入门资料推荐
    前言群里很多入门小白不知道如何入门Flutter,水一篇文章简单介绍下本人学习过程中一些参考资料,方便Flutter小白少走弯路。非权威,推荐只针对本人经验来的说,大佬们不喜......
  • 《谁有惠根斯原理的电磁场叠加证明?要完整数学证明过程》 回复
    《谁有惠根斯原理的电磁场叠加证明?要完整数学证明过程》     https://tieba.baidu.com/p/8241825902    。  用 麦克斯韦方程 证明啊,  这不......