flutter布局更新

news2024/11/15 17:41:58

理论上,某个组件的布局变化后,就可能会影响其他组件的布局,所以当有组件布局发生变化后,最笨的办法是对整棵组件树 relayout(重新布局)!但是对所有组件进行 relayout 的成本还是太大,所以我们需要探索一下降低 relayout 成本的方案。实际上,在一些特定场景下,组件发生变化后我们只需要对部分组件进行重新布局即可(而无需对整棵树 relayout )

布局边界(relayoutBoundary)

假如有一个页面的组件树结构如图所示。

假如 Text3 的文本长度发生变化,则会导致 Text4 的位置和 Column2 的大小也会变化;又因为 Column2 的父组件 SizedBox 已经限定了大小,所以 SizedBox 的大小和位置都不会变化。所以最终我们需要进行 relayout 的组件是:Text3、Column2,这里需要注意:

  1. Text4 是不需要重新布局的,因为 Text4 的大小没有发生变化,只是位置发生变化,而它的位置是在父组件 Column2 布局时确定的。
  2. 很容易发现:假如 Text3 和 Column2 之间还有其他组件,则这些组件也都是需要 relayout 的。

在本例中,Column2 就是 Text3 的 relayoutBoundary (重新布局的边界节点)。每个组件的 renderObject 中都有一个 _relayoutBoundary 属性指向自身的布局边界节点,如果当前节点布局发生变化后,自身到其布局边界节点路径上的所有的节点都需要 relayout。

那么,一个组件是否是 relayoutBoundary 的条件是什么呢?这里有一个原则和四个场景,原则是“组件自身的大小变化不会影响父组件”,如果一个组件满足以下四种情况之一,则它便是 relayoutBoundary :

  1. 当前组件父组件的大小不依赖当前组件大小时;这种情况下父组件在布局时会调用子组件布局函数时并会给子组件传递一个 parentUsesSize 参数,该参数为 false 时表示父组件的布局算法不会依赖子组件的大小。

  2. 组件的大小只取决于父组件传递的约束,而不会依赖后代组件的大小。这样的话后代组件的大小变化就不会影响自身的大小了,这种情况组件的 sizedByParent 属性必须为 true(具体我们后面会讲)。

  3. 父组件传递给自身的约束是一个严格约束(固定宽高,下面会讲);这种情况下即使自身的大小依赖后代元素,但也不会影响父组件。

  4. 组件为根组件;Flutter 应用的根组件是 RenderView,它的默认大小是当前设备屏幕大小。

对应的代码实现是 

// parent is! RenderObject 为 true 时则表示当前组件是根组件,因为只有根组件没有父组件。
if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject) {
  _relayoutBoundary = this;
} else {
  _relayoutBoundary = (parent! as RenderObject)._relayoutBoundary;
}

markNeedsLayout

当组件布局发生变化时,它需要调用 markNeedsLayout 方法来更新布局,它的功能主要有两个:

  1. 将自身到其 relayoutBoundary 路径上的所有节点标记为 “需要布局” 。
  2. 请求新的 frame;在新的 frame 中会对标记为“需要布局”的节点重新布局。

核心源码

void markNeedsLayout() {
   _needsLayout = true;
  if (_relayoutBoundary != this) { // 如果不是布局边界节点
    markParentNeedsLayout(); // 递归调用前节点到其布局边界节点路径上所有节点的方法 markNeedsLayout
  } else {// 如果是布局边界节点 
    if (owner != null) {
      // 将布局边界节点加入到 pipelineOwner._nodesNeedingLayout 列表中
      owner!._nodesNeedingLayout.add(this); 
      owner!.requestVisualUpdate();//该函数最终会请求新的 frame
    }
  }
}

 flushLayout()

markNeedsLayout 执行完毕后,就会将其 relayoutBoundary 节点添加到 pipelineOwner._nodesNeedingLayout 列表中,然后请求新的 frame,新的 frame 到来时就会执行 drawFrame 方法

Layout流程

如果组件有子组件,则在 performLayout 中需要调用子组件的 layout 方法先对子组件进行布局,我们看一下 layout 的核心流程:

void layout(Constraints constraints, { bool parentUsesSize = false }) {
  RenderObject? relayoutBoundary;
  // 先确定当前组件的布局边界
  if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject) {
    relayoutBoundary = this;
  } else {
    relayoutBoundary = (parent! as RenderObject)._relayoutBoundary;
  }
  // _needsLayout 表示当前组件是否被标记为需要布局
  // _constraints 是上次布局时父组件传递给当前组件的约束
  // _relayoutBoundary 为上次布局时当前组件的布局边界
  // 所以,当当前组件没有被标记为需要重新布局,且父组件传递的约束没有发生变化,
  // 且布局边界也没有发生变化时则不需要重新布局,直接返回即可。
  if (!_needsLayout && constraints == _constraints && relayoutBoundary == _relayoutBoundary) {
    return;
  }
  // 如果需要布局,缓存约束和布局边界
  _constraints = constraints;
  _relayoutBoundary = relayoutBoundary;

  // 后面解释
  if (sizedByParent) {
    performResize();
  }
  // 执行布局
  performLayout();
  // 布局结束后将 _needsLayout 置为 false
  _needsLayout = false;
  // 将当前组件标记为需要重绘(因为布局发生变化后,需要重新绘制)
  markNeedsPaint();
}

简单来讲布局过程分以下几步:

  1. 确定当前组件的布局边界。

  2. 判断是否需要重新布局,如果没必要会直接返回,反之才需要重新布局。不需要布局时需要同时满足三个条件:

    • 当前组件没有被标记为需要重新布局。

    • 父组件传递的约束没有发生变化。

    • 当前组件的布局边界也没有发生变化时。

  3. 调用 performLayout() 进行布局,因为 performLayout() 中又会调用子组件的 layout 方法,所以这时一个递归的过程,递归结束后整个组件树的布局也就完成了。

  4. 请求重绘。

总结

在进行布局的时候,Flutter 会以 DFS(深度优先遍历)方式遍历渲染树,并 将限制以自上而下的方式 从父节点传递给子节点。子节点若要确定自己的大小,则 必须 遵循父节点传递的限制。子节点的响应方式是在父节点建立的约束内 将大小以自下而上的方式 传递给父节点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1549117.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

目前2024年腾讯云4核8G服务器租用优惠价格表

2024年腾讯云4核8G服务器租用优惠价格:轻量应用服务器4核8G12M带宽646元15个月,CVM云服务器S5实例优惠价格1437.24元买一年送3个月,腾讯云4核8G服务器活动页面 txybk.com/go/txy 活动链接打开如下图: 腾讯云4核8G服务器优惠价格 轻…

车载以太网AVB交换机 TSN交换机 时间敏感网络 6端口 百兆 SW100TSN

SW100 TSN时间敏感网络AVB交换机 为6端口百兆车载以太网交换机,其中包含5通道100BASE-T1泰科MATEnet接口和1个通道100/1000BASE-T标准以太网(RJ45接口),可以实现纳米级时间同步,车载以太网多通道交换,Bypass数据采集和监控等功能&…

B2 PRO WordPress主题:多功能商用主题,助力资讯、资源、社交、商城、圈子、导航一站式解决

B2 PRO WordPress主题:多功能商用主题,助力资讯、资源、社交、商城、圈子、导航一站式解决 一、产品概述 B2 PRO WordPress主题,作为一款多功能商用主题,致力于为用户提供一站式的内容管理与网站建设服务。它集资讯发布、资源共享…

4.常用CMD命令

扩展一个小点: 在很多资料中都说成是DOS命令,其实是不对的。真正的DOS命令是1981年微软和IBM出品的MS-DOS操作系统中的命令才叫做DOS命令。 而在Windows中,win98之前的操作系统是以非图形化的DOS为基础的,可以叫做DOS命令。到了…

精酿啤酒:特殊酵母的发酵特性与风味表现

Fendi Club啤酒在酿造过程中采用了特殊的酵母,这些酵母具有与众不同的发酵特性和风味表现,为啤酒带来了与众不同的风味和口感。 Fendi Club啤酒使用的酵母种类繁多,包括艾尔酵母和拉格酵母等。这些不同种类的酵母在发酵过程中具有不同的特性和…

unity学习(70)——编译游戏发生错误2

1.全屏问题其实无所谓,windows用tab可以切出来的。 2.现在主要问题是服务器try了以后虽然不崩溃了,但不再显示2个实例对象了,unity和exe此时都只能看到一个实例对象 2.1把之前报错位置的try-catch先注释掉 2.2 unity中此时登录666账号&…

0103设计算法-算法基础-算法导论第三版

文章目录 一、分治法二、分析分治算法结语 我们可以选择使用的算法设计技术有很多。插入排序使用了增量方法:在排序子数组 A [ 1 ⋯ j − 1 ] A[1\cdots j-1] A[1⋯j−1]后,将单个元素 A [ j ] A[j] A[j]插入子数组的适当位置,产生排序好的子…

java-获取1688网站商家信息----简单应用

1.下载google浏览器 注: 苹果电脑下载 旧版本google浏览器 点设置时会自动更新, (卸载重装),运行时版本和驱动不匹配会报错 第三方网站下载链接:旧版本(安装后老是提示更新,最新版本没有找到对应的驱动,不能更新它) Google Chrome 64bit OS X版_chrome浏览器,chrome插件,谷歌浏…

基于Springboot的疫情隔离酒店管理系统(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的疫情隔离酒店管理系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系…

完全二叉树的层序遍历[天梯赛]

文章目录 题目描述思路 题目描述 输入样例 8 91 71 2 34 10 15 55 18 输出样例 18 34 55 71 2 10 15 91思路 完全二叉树最后一层可以不满,但上面的每一层的节点数都是满的 后序遍历的顺序为"左右根",我们可以用数组模拟完全二叉树,…

奶瓶哪个牌子的比较好?适合新生儿的奶瓶分享

每一位新手家长都要选购很多东西,而必备的无疑就是新生儿奶瓶了。如果你不知道要给宝宝选什么品牌的奶瓶好,不懂哪些材质符合安全无毒标准。那么收藏这篇文章就对了,作为一名测评博主,我近期测评了多款全网热议的奶瓶,…

【机器学习300问】54、如何找到有效的组合特征?

一、为什么需要去寻找有效的组合特征? 因为并不是所有的特征组合都会意义,都能带来价值。 例如在房价预测场景中,卧室数量和浴室数量的比值有意义,但房屋面积与建造年份相组合作为新的组合特征,可能就没有实际含义&…

面试经典150题【111-120】

文章目录 面试经典150题【111-120】67.二进制求和190.颠倒二进制位191.位1的个数136.只出现一次的数字137.只出现一次的数字II201.数字范围按位与5.最长回文子串97.交错字符串72.编辑距离221.最大正方形 面试经典150题【111-120】 六道位运算,四道二维dp 67.二进制…

[HackMyVM]靶场quick5

kali:192.168.56.104 靶机:192.168.56.134 端口扫描 # nmap 192.168.56.134 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-27 19:08 CST Nmap scan report for careers.quick.hmv (192.168.56.134) Host is up (0.000056s latency). Not shown: 998 closed tcp p…

Unity编辑器功能将AB资源文件生成MD5码

将路径Application.dataPath/ArtRes/AB/PC文件夹下所有的Ab包文件生成MD5吗,通过文件名 文件长度MD5‘|’的格式拼接成字符串写入到资源对比文件abCompareInfo.txt中。 将路径pathFile扥文件生成MD5码

C语言学习之环境搭建【建议收藏】

学生时代,我们一般使用的VC【Microsoft Visual C 2010(学习版)】进行学习,该篇博客主要记录如何安装VC,非常详细,适合入门的小白,奶妈级别安装教程,建议收藏。 准备好软件安装包&…

LeetCode刷题--- Dijkstra 求最短路径

首先是图的表示,邻接矩阵和邻接表。实现看代码 邻接矩阵:二维数组, matrix[a][b] 表示 从a可以指向b无向图而言, matrix[a][b]matrix[b][a],比如可以定义matrix[a][b]1表示ab是连接的,matrix[a][b]0表示ab…

Docker进阶:Docker Swarm —弹性伸缩调整服务的副本数量

Docker进阶:Docker Swarm —弹性伸缩调整服务的副本数量 1、 创建一个Nginx服务(Manager节点)2、查看服务状态(Manager节点)3、测试访问(Worker节点)4、查看服务日志(Manager节点&am…

有效三角形的个数【双指针】

1.优化版暴力求解 如果能构成三⻆形,需要满⾜任意两边之和要⼤于第三边。实际上只需让较⼩的两条边之和⼤于第三边即可。将原数组排序,从⼩到⼤枚举三元组,这样三层 for 循环枚举出的三元组只需判断较⼩的两条边之和是否⼤于第三边。 class…

2024/3/24周报

文章目录 摘要Abstract文献阅读题目引言创新点数据处理研究区域和数据缺失值处理水质相关分析 方法和模型LSTMAttention机制AT-LSTM模型 实验结果 深度学习transformer代码实现1 模型输入1.1 Embedding层1.2 位置编码 2 Encoder2.1 编码器2.2 编码器层2.3注意力机制2.4多头注意…