flutter布局更新

卡片使用_用 Flutter 实现探探卡片布局 前言前几天写了一个 Fluter 插件 tcard,用来实现类似于探探卡片的布局。效果如下,本文讲解如何使用 Stack 控件实现这个布局。在线查看初识 StackStack 是一个有多子项的控件,它会将自己的子项相对于自身边缘进行定位,后面的子项会覆盖前面的子项。通常用来实现将一个控件覆盖于另一个控件之上的布局,比如在一张图片上显示一些文字。子项的默认位置在 Stack 左上角,也可以用 Ali... 阅读详情

理论上,某个组件的布局变化后,就可能会影响其他组件的布局,所以当有组件布局发生变化后,最笨的办法是对整棵组件树 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(深度优先遍历)方式遍历渲染树,并 将限制以自上而下的方式 从父节点传递给子节点。子节点若要确定自己的大小,则 必须 遵循父节点传递的限制。子节点的响应方式是在父节点建立的约束内 将大小以自下而上的方式 传递给父节点。

Flutter之RenderView RenderObject ParentData知识点梳理 RenderView RenderObject ParentData知识点梳理 前言一、参考资料二、RenderView1、Flutter runApp的具体流程:2、 RenderView的创建3、RenderObjectToWidgetElement 构建详解 前言 本篇文章详细的说明了RenderView ,RenderObject在Flutter框架体系中的位置,为进一步分析Flutter其他相关做知识储备,其实本篇的内容只要读者自己简单追踪下其源码,就可以轻松了解 一、参考资料 这些相关资料大部分 阅读详情

相关推荐

统信UOS开发环境支持Java

集成了JDK和多种IDE,为开发者提供了从代码编写、编译、调试到部署的一站式开发解决方案。

RZer的博客 2254

57、Flutter核心原理--布局Layout过程

布局(Layout)过程 Layout(布局)过程主要是确定每一个组件的布局信息(大小和位置),Flutter 的布局过程如下: 父节点向子节点传递约束(constraints)信息,限制子节点的最大和最小宽高。 子节点根据约束信息确定自己的大小(size)。 父节点根据特定布局规则(不同布局组件会有不同的布局算法)确定每一个子节点在父节点布局空间中的位置,用偏移 offset 表示。 递归整个过程,确定出每一个节点的位置的大小和位置。 可以看到,组件的大小是由自身决定的,而组件的位置是由父组件决

wywinstonwy的专栏 1万+

Linux 音频驱动(六) ALSA音频驱动之PCM Write数据传递过程

目录1. 前言2. PCM Data Flow3. 总结 1. 前言 本文,我们将以回放(Playback,播放音频)为例,讲解PCM Data是如何从用户空间到内核空间,最后传递到Codec。 在Linux 音频驱动(一) ASoC音频框架简介中,我们给出了回放(Playback)PCM数据流示意图: 对于Linux来说,由于分为 user space 和kernel space,而且两者之间不能随便互相访问。因此用户如果播放音频,则需要调用copy_from_user()将用户数据从user spa

_Modest_的博客 1万+

Flutter框架分析(七)-relayoutBoundary

1. 前言 在Flutter框架分析(四)-RenderObject一文中,我们简单介绍了RenderObject中一个重要成员变量:RelayoutBoundary。下面我们简单回顾下RelayoutBoundary的主要作用。 当一个组件的大小被改变时,其parent的大小可能也会被影响,因此需要通知其父节点。如果这样迭代上去,需要通知整棵RenderObject Tree重新布局,必然会影响布局效率。因此,Flutter通过RelayoutBoundary将RenderObject Tree分段,如果

zuoluohust的博客 646

RFC-only 与 SAProuter 场景下,让 Claude 真正参与 SAP ABAP 开发

SAP ABAP 开发这几年正在出现一个很有意思的变化。过去我们说开发工具,脑子里大多是 SE80、SE38、SE24、SEGW、Eclipse ADT,再往后是 BAS、VS Code、abapGit、ATC、CI/CD。现在又多了一层,Claude Code、Claude Desktop 这类 AI 编程助手开始通过 MCP 进入开发现场,不只是写一段示例代码,而是能读系统里的 ABAP 对象、搜索包、改源码、跑检查、辅助重构。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1617

18、公开可用的PPG数据库介绍

本文介绍了多个公开可用的PPG(光电容积描记)数据库,包括PPG-BP数据库、MIMIC II波形数据库、运动期间手腕PPG数据库以及指尖PPG与呼吸数据库等。这些数据库提供了丰富的生理信号数据,适用于动脉血压检测、呼吸频率估计、运动干扰去除以及基于PPG的生物特征识别等研究。每个数据库的数据来源、受试者信息、信号特点和下载方式均有详细介绍,并展示了如何利用这些数据库进行信号分析和算法评估。

salt的博客 387

深入理解Flutter 源码刷新机制--------relayoutBoundary的妙用

大家有没有想过,当子widget属性变化后,通过setState通知底层引擎刷新,那么当前页面上的所有Widget都会刷新吗,准确说应该是RenderObject Tree会整个刷新吗? 聪明的你肯定能想的到,当然不会把整个RenderObject Tree刷新 当一个组件的大小被改变时,其parent的大小可能也会被影响,因此需要通知其父节点。如果这样迭代上去,需要通知整棵RenderObject Tree重新布局,必然会影响布局效率。因此,Flutter通过RelayoutBoundary将Rend

bawomingtian123的专栏 2271

用 SAP-ABAP-1 把 ABAP 代码读懂:从 Generative AI Hub Orchestration 到 Joule 落地的实战指南

SAP-ABAP-1 是 SAP 推出的 ABAP 专用基础模型,专注于代码解释与理解。它能显著降低企业遗留系统的维护成本,帮助开发人员快速掌握复杂业务逻辑。该模型通过 SAP Generative AI hub 托管,支持 128,000 tokens 的上下文长度,适合分析大型 ABAP 类和 CDS 视图。典型应用场景包括代码解释、迁移辅助和云合规检查。调用需通过 Orchestration service 进行,确保企业级安全治理。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1211

Flutter 绘制流程分析与代码实践

Render Tree 的创建过程 RenderObject 的类型 我们知道 Element 主要分为负责渲染的 RenderObjectElement 和负责组合的 ComponentElement 两大类,而创建 RenderObject 节点的是前者 mount() 方法中调用的 RenderObjectWidget.createRenderObject() 方法。 该方法是一个抽象方法,需要子类实现,对于不同的布局的 Widget 创建的 RenderObject 类型也不一样,在 Rend

Dream It Possible 1388

CAPL概述与环境搭建

CANoe和CANalyzer是Vector公司开发的两款用于汽车电子系统开发和测试的工具。CANoe主要用于网络开发、仿真和测试,而CANalyzer则主要用于网络分析和诊断。两者都支持CAPL脚本语言,可以用于编写复杂的测试脚本和仿真模型。CAPL Browser是CANoe/CANalyzer中用于编写、编辑和调试CAPL脚本的工具。它提供了一个集成的开发环境,支持语法高亮、代码自动补全、调试等功能。菜单栏:包含文件操作、编辑、编译、调试等功能。工具栏。

闲人编程的博客 1661

Python爬虫实战:逆向解析天猫商品详情API,精准捕获规格、SKU与促销活动

及浏览器开发者工具),绕过前端渲染的复杂性,直接逆向分析并调用其内部数据接口,从而高效、稳定地抓取商品的关键信息,包括商品规格、多维度SKU信息以及复杂的促销活动。print(f"SKU ID: {sku.sku_id}, 价格: ¥{sku.price}, 库存: {sku.stock}, 规格: {sku.props}")当你访问一个商品链接时,浏览器首先会加载一个几乎为空的HTML骨架,然后通过执行大量的JavaScript代码,向后台服务器发起多个异步请求,最终将获取到的数据填充到页面中。

2201_76125261的博客 1129

Flutter渲染流程解析

Widget-Element-RenderObject 一. Flutter的渲染流程 1.1. Widget-Element-RenderObject关系 3棵tree的关系 1.2. Widget是什么? image-20200302153223929 官方对Widget的说明: Flutter的Widgets的灵感来自React,中心思想是构造你的UI使用这些Widgets。 Widget使用配置和状态,描述这个View(界面)应该长什么样子。 当一个W.

大灰狼的小绵羊哥哥的博客 1285

PyQt5开发应聘简历模版

该工具旨在帮助用户对Excel、CSV格式的数据进行快速导入、分析及可视化展示,支持折线图、柱状图、饼图等多种图表类型,提供数据筛选、排序、统计等功能,适用于企业数据分析人员日常工作。:一款用于本地文件管理的桌面应用,支持文件的新建、复制、移动、删除、重命名等基本操作,具备文件搜索、分类整理、批量操作及文件信息查看等功能,提升用户文件管理效率。:熟悉QSS(Qt Style Sheet)样式表,可对PyQt5界面进行个性化美化,包括控件颜色、字体、边框、布局等样式定制,提升应用视觉体验。

ybmzlqzj的博客 83

flutter引导页、布局、定时器、网络异步数据更新

疫情刚好静下心来回归过去的工作,博主要开始学习flutter,博主会边学习边实战项目连续连贯实现,大约一周会出一篇,源码地址,开源不易,麻烦动手点星,谢谢,本开源不做商业使用,里面涉及用到api接口资源等只供学习,项目开发会分博客文章,请点击链接到对应的文章中浏览,建议其实万变不离其中,说到底还是离不开原生,学习之前往补充原生知识,本片主要讲的是引导页,其中涉及到技术点层叠布局、相对定位、容器、定...

Apple_hsp的专栏 2922

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

flutter text 左对齐_Flutter 常用布局详解(更新...)

Flutter 项目中常用的布局详情,及封装和使用,快速开发项目.以及手势事件和滚动事件的使用Scaffold 导航栏的实现,有些路由页可能会有抽屉菜单(Drawer)以及底部Tab导航菜单等const Scaffold({ Key key, this.appBar,//标题栏 this.body,//内容 this.floatingActionButton,//悬...

weixin_39620662的博客 1662

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

bootstrap导航栏垂直布局_Flutter 常用布局详解(更新...)

Flutter 项目中常用的布局详情,及封装和使用,快速开发项目.以及手势事件和滚动事件的使用Scaffold 导航栏的实现,有些路由页可能会有抽屉菜单(Drawer)以及底部Tab导航菜单等const Flutter 中自带的material样式的标题栏,首先看一下AppBar具有哪些属性,代码如下:AppBar悬浮button 属性详解const 底部导航栏BottomNavigationBa...

weixin_39809793的博客 686

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Flutter(二) 布局和列表

对Android和Flutter布局上的构建差异,有一个整体的认识。

weixin_51022898的博客 980

给Android开发者Flutter上手指南

目录 LinearLayout 在Flutter中等价于什么(Android)? RelativeLayout 在Flutter中等价于什么(Android)? 如何使用widget定义布局属性? 如何分层布局? 如何设置布局样式? ScrollView在Flutter中等价于什么? 谁是Flutter的列表组件? 如何知道点击了列表中哪个item? 如何动态更新ListView? LinearLayout 在Flutter中等价于什么(Android)? 在Android中,使用LinearLayo.

fengyuzhengfan的专栏 703

Flutter开发(五):Flutter布局与列表

1.Flutter 中的线性布局(Android 中 LinearLayout) 在 Flutter 中,可以使用 Row (横向)和 Column (纵向) widget 来实现同样的效果: void main() { runApp(MaterialApp(home: MyApp())); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return R

wuqingsen1的博客 926

Flutter响应式布局利器:Responsive Scaffold 介绍

Flutter响应式布局利器:Responsive Scaffold 介绍 1. 项目基础介绍 Responsive Scaffold 是一个由 Flutter 社区维护的开源项目,主要使用 Dart 语言编写。该项目旨在帮助开发者快速实现响应式布局,使得应用能够在不同尺寸的设备上(如手机和平板)展现出最佳的用户界面。通过这个项目,开发者可以节省大量的时间和工作量,尤其是在构建跨平台应用时。 2....

gitblog_00020的博客 980

给 iOS 开发者的 Flutter 指南

在 iOS 里,你可以直接继承UIView或者使用已经存在的视图,然后重写并实现对应的方法来达到想要的效果。在 Flutter 里,构建自定义 widget 需要通过组合一些小的 widget(而不是对它们进行扩展)来实现。例如,应该如何构建一个初始方法中就包含文本标签的?需要创建一个合成一个和一个文本标签的 CustomButton,而不是继承@override与其他 Flutter widget 一样的用法,下面我们使用@override导航。

2301_79098336的博客 1671

Flutter | 布局流程

浅谈布局过程 Layout(布局)过程中是确定每一个组件的信息(大小和位置),Flutter 中的布局过程如下: 1,父节点向子节点传递约束信息,限制子节点的最大和最小宽高。 2,子节点根据自己的约束信息来确定自己的大小(Szie)。 3,父节点根据特定的规则(不同的组件会有不同的布局算法)确定每一个子节点在父节点空间中的位置,用偏移 offset表示。 4,递归整个过程,确定出每一个节点的位置和大小。 可以看到,组件的大小是由自身来决定的,而组件的位置是由父组件来决定的。 Flutter 中布局类组件有很

345丶 2084

Flutter 三棵树

Flutter框架的核心机制围绕"三棵树"展开:Widget树作为不可变的配置蓝图,Element树负责对比更新和生命周期管理,RenderObject树执行布局、绘制和命中测试。Widget声明UI需求,Element对比新旧Widget决定复用或重建,RenderObject处理具体渲染。当布局改变时,若Widget类型不同(如Column变Row),会触发Element和RenderObject的销毁重建;若仅属性变化(如文本修改),则复用现有节点仅局部更新。这种分层设计配合Key

lxjlxj2333的博客 1145

Flutter 跨平台渲染核心:渲染树构建与更新机制深度剖析

渲染树是 Flutter 渲染管道的核心数据结构,由。

2501_93891234的博客 724

Flutter流式瀑布布局组件推荐

Flutter流式瀑布布局组件推荐 本文将为您介绍一个开源项目:Flutter流式瀑布布局组件(WaterfallFlow),该项目使用Dart语言开发,为Flutter开发者提供了一个简单易用的瀑布流布局解决方案。 1. 项目基础介绍和主要编程语言 项目名称:WaterfallFlow 主要编程语言:Dart WaterfallFlow 是一个基于 Flutter 的开源组件,它能够帮助开发者快...

gitblog_00278的博客 462

跟我学flutter:细细品Widget(四)Widget 渲染过程 与 RenderObjectWidget

前言 StatelessWidget 和 StatefulWidget 只是用来组装控件的容器,并不负责组件最后的布局和绘制。在 Flutter 中,布局和绘制工作实际上是在 Widget 的另一个子类 RenderObjectWidget 内完成的。 RenderObjectWidget为RenderObjectElement提供配置信息。 RenderObjectElement包装了RenderObject,RenderObject为应用程序提供真正的渲染。 源码 abstract class Rend

s297165331的专栏 1408
上一篇: Flutter Widgets体系结构
下一篇: Flutter 绘制原理
jsPao
博客等级 码龄7年 549粉丝 107原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值