总结了30个例子之后,我悟到了Flutter的布局原理

Flutter布局之——理解Constraints 最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。 阅读详情

总结了30个例子之后,我悟到了Flutter的布局原理

学习最忌盲目,无计划,零碎的知识点无法串成系统。学到哪,忘到哪,面试想不起来。这里我整理了Flutter面试中最常问以及Flutter framework中最核心的几块知识,大概二十篇左右文章分析,欢迎关注,共同进步。

 

导语

UI原理部分:

1、为什么不建议大家使用setState()。

2、面试官问我State的生命周期,该怎么回答

3、Flutter的布局约束原理

4、实战Flutter绘制过程

读完本文你将收获:Flutter各种控件是如何实现布局的

引言

一切的开始来自于这个神奇的网站(深入理解Flutter布局约束),其中提供了30个让奇奇怪怪的布局例子让我大涨见识(30个相当不讲武德!!),有这样的

这样的

还有这样的

 

不得不说确实覆盖了很多场景!可是对于我这种记性不好的懒鬼来说,看完30个例子真的是太!费!劲!了!而且看完就忘!!实际中大概率不会出现一模一样的情况。所以我就在寻思,这背后究竟是啥原理可以我下次不用反复复习这30个例子呢?这就引出了今天的主题:Flutter的布局原理

正片开始:先宏观看看Flutter组件的分类

在原生上我们知道一个View控件的渲染过程大致分为onMeasure()[知道有多大],onLayout()[知道该放那],onDraw()[知道长啥样]三个过程。但Flutter的UI体系思路和这个不太一样,首先在Flutter的组件体系中,并非所有的Widget都会渲染到最后的页面上,整个Widget大概可以分为三类组合类、代理类、绘制类 -[这点面试必问!!]-

 

 

平时我们使用到最多的StatelessWidget和StatefulWidget其实只是组合类的控件,实际上他并不负责绘制,所有我们在屏幕上看到的UI最终几乎都会通过RenderObjectWidget实现。而RenderObjectWidget中有个createRenderObject()方法生成RenderObject对象,RenderObject实际负责实际的layout()和paint()。例如我们最常使用的Container组件其实只是一个组合类的控件,在其中封装了多个负责绘制的原子组件。想详细了解RenderObjectWidget可以看看深入研究Flutter布局原理写得非常好


开胃小菜:RenderObject的的绘制过程

那RenderObject是如何完成渲染的呢,在原来我一直在错误的使用 setState()?中分析过,Flutter的渲染流程关键在于drawFrame()方法中

void drawFrame() {
  //在这之前已经完成了build()
  pipelineOwner.flushLayout();
  pipelineOwner.flushCompositingBits();
  pipelineOwner.flushPaint();
  renderView.compositeFrame(); // this sends the bits to the GPU
  pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
}

整个过程和原生分为三个阶段build(),layout(),paint()。build()方法由组合类和代理类Widget实现,layout()和paint()由RenderObject实现。这里设计思路和原生不太一样,在原生中layout()方法一般由ViewGroup实现,他需要规定child控件的位置。这样他的子节点就只用关心绘制即可。

而Flutter中的layout()更接近理解为Measure(!!理解这点非常重要,不能用原生的思路去学习),它的职能主要是计算控件自身的尺寸和位置偏移。这里的计算是一个从最顶级的节点开始传递约束,从下开始返回测量结果的过程

 

测量结果我们很好理解,就是一个控件实际的宽高。而约束是个啥玩意儿??


硬菜来了: What's Constraints

约束Constraints 在Flutter中是一种布局协议,Flutter中有两大布局协议BoxConstraints和SliverConstraints。对于非滑动的控件例如Padding,Flex等一般都使用BoxConstraints盒约束。

BoxConstraints({
    this.minWidth,
    this.maxWidth,
    this.minHeight,
    this.maxHeight,
  });

看起来非常好理解,在盒约束中,只会限制子控件的最大最小宽高。经过我搜刮了网上几乎所有的布局原理文章之后,对于这个约束这个约束可以这样总结。 首先这个约束可以根据最大最小值分为两大类

  • 1、 tight(紧约束):当max和min值相等时,这时传递给子类的是一个确定的宽高值。
const BoxConstraints.expand({
    double width,
    double height,
  }) : minWidth = width ?? double.infinity,
       maxWidth = width ?? double.infinity,
       minHeight = height ?? double.infinity,
       maxHeight = height ?? double.infinity;

这个约束的使用的地方主要有两个

一个在Container中,当Container的 child==null&&||(constraints == null || !constraints.isTight))时。 另一个ModalBarrier,这个组件我们不太熟悉,但查看调用发现被嵌套在了Route中,所以每次我们push一个新Route的时候,默认新的页面就是撑满屏幕的模式。

  • 2、loose(松约束):当max和min不相等的时候,这种时候对子类的约束是一个范围,称为松约束。
BoxConstraints.loose(Size size)
    : minWidth = 0.0,
      maxWidth = size.width,
      minHeight = 0.0,
      maxHeight = size.height;

在我们最常使用的Scaffold组件中就采用了这种布局,所以Scaffold对于子布局传递的是一个松的约束。


酣畅过瘾: 举几个栗子

了解了上面的基础概念之后,我们先来看看如何对一些场景进行分析。当我们想知道一个控件的布局过程是怎样的,可以参考:

在你的代码中找到一个 Column 并跟进到它的源代码。为此,请在 (Android Studio/IntelliJ) 中使用 command+B(macOS)或 control+B(Windows/Linux)。你将跳到 basic.dart 文件中。由于 Column 扩展了 Flex,请导航至 Flex 源代码(也位于 basic.dart 中)。 向下滚动直到找到一个名为 createRenderObject() 的方法。如你所见,此方法返回一个 RenderFlex。它是 Column 的渲染对象,现在导航到 flex.dart 文件中的 RenderFlex 的源代码。 向下滚动,直到找到 performLayout() 方法,由该方法执行列布局。

根据这个方法,我们试着分析几个有意思的栗子。

案例1(来自样例一)

如图,如果我们直接返回一个红色Container,这个时候他会撑满整个屏幕。首先Container是一个组合类的Widget,并不负责渲染。查看他的build方法,在这种情况下返回了三层RenderObject RenderDecoratedBox,RenderLimitedBox,RenderConstrainedBox

这三个类都继承自RenderProxyBox,这个类混入了RenderProxyBoxMixin,布局方法就在里面:

@override
  void performLayout() {
    if (child != null) {
      child.layout(constraints, parentUsesSize: true);
      size = child.size;
    } else {
      performResize();
    }
  }

其实从这个类的名称我们可知一二,这是个代理类的渲染对象,如果他有子节点的的时候他会把自己父节点的约束constraints传递给节点,然后使用子节点的尺寸作为自己的。 那么最外层的RenderDecoratedBox的约束是什么呢。前面其实也提到了在紧约束中,BoxConstraints.expand被用在了Route上,所以每个页面默认是撑满屏幕的。这个约束就一直向下传递

但在最下面的RenderConstrainedBox重写了performLayout方法

@override
  void performLayout() {
    if (child != null) {
      child.layout(_additionalConstraints.enforce(constraints), parentUsesSize: true);
      size = child.size;
    } else {
      size = _additionalConstraints.enforce(constraints).constrain(Size.zero);
        }
  }

其实和上面差不多,不过对RenderConstrainedBox我们可以添加约束信息_additionalConstraints属性,查看Container的build方法可知这个约束在这种情况下为BoxConstraints.expand ,在layout的时候也会被考虑。由于RenderConstrainedBox下没有child了所以走

size = _additionalConstraints.enforce(constraints).constrain(Size.zero);
  ///返回新的框约束,它尊重给定的约束,同时与原始约束尽可能接近
  BoxConstraints enforce(BoxConstraints constraints) {
    return BoxConstraints(
      minWidth: minWidth.clamp(constraints.minWidth, constraints.maxWidth),
      maxWidth: maxWidth.clamp(constraints.minWidth, constraints.maxWidth),
      minHeight: minHeight.clamp(constraints.minHeight, constraints.maxHeight),
      maxHeight: maxHeight.clamp(constraints.minHeight, constraints.maxHeight),
    );
  }

关键在于enforce这个方法,这里他接受到的参数是来自页面中的紧约束(max=min=屏幕宽度),这样无论你为自身添加的约束_additionalConstraints是多少,他都会返回一个紧约束(max=min=屏幕宽度),而这个约束被再次向下传递

最终这个Container渲染的时候,撑满了整个屏幕!

案例2(来自样例9)

这个例子案例1外层增加了一个约束,并且内部也为自己设置了高度。你可能会猜想 Container 的尺寸会在 70 到 150 像素之间,但并不是这样,Container仍然撑满了整个屏幕。我们还是来看Render树的结构

整个树构造变成了这样,我们一步步来看。 首先最外层的ConstrainedBox接收到来自页面的紧约束(max=min=屏幕宽度),计算采用上面的计算方式还是得到了一个同样的约束,之后这个约束向下传递,就变成和案例一一样的情况


总结

1、Widget大概可以分为三类组合类、代理类、绘制类

2、所有我们在屏幕上看到的UI最终几乎都会通过RenderObjectWidget实现。而RenderObjectWidget中有个createRenderObject()方法生成RenderObject对象,RenderObject实际负责实际的layout()和paint()。

3、Container组件其实只是一个组合类的控件,在其中封装了多个负责绘制的原子组件。

4、layout() 职能主要是计算控件自身的尺寸和位置偏移

5、整个布局过程就是向下约束 向上传值的过程

6、盒约束中有两种:

  • tight(紧约束):当max和min值相等时,这时传递给子类的是一个确定的宽高值。
  • loose(松约束):当max和min不相等的时候,这种时候对子类的约束是一个范围,称为松约束

一句话总结:

最后

在这里我也分享一份由几位大佬一起收录整理的 Android学习PDF+架构视频+面试文档+源码笔记 ,并且还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料……

这些都是我闲暇时还会反复翻阅的精品资料。可以有效的帮助大家掌握知识、理解原理。当然你也可以拿去查漏补缺,提升自身的竞争力。

如果你有需要的话,可以前往 GitHub 自行查阅。

相信一定可以帮助到大家!

最新首发——boss直聘爬虫 本文介绍了使用Python开发Boss直聘爬虫的核心思路和技术要点。通过模拟浏览器访问搜索页面获取Cookie,然后构建API请求获取职位数据。关键步骤包括:1)使用DrissionPage库初始化浏览器;2)模拟用户浏览行为获取必要参数;3)设置完整的请求头信息;4)通过POST请求获取JSON格式的职位数据。文章提供了详细的代码实现,包括浏览器模拟、API请求构建、数据处理等核心功能模块,并强调了最新版接口改为POST访问的特点。该爬虫可自动翻页采集数据并保存为Excel文件,适用于安全实习等职位信息的 阅读详情

相关推荐

Unity WebGL项目如何实现画布透明,完美融入网页背景(附.jslib文件与完整配置)

本文详细解析了Unity WebGL项目实现画布透明化的技术原理与实战步骤,从.jslib文件配置到前端框架集成,帮助开发者解决默认背景色问题,实现3D内容与网页设计的无缝融合。重点介绍了透明化核心机制、常见误区及React/Vue等现代框架中的最佳实践方案。

weixin_31896061的博客 301

【Flutter】布局——BoxConstraints(盒约束)

BoxConstraints 作为Container的属性,设置Container的宽高,以约束子widget的大小 可类比web中给盒子设置最大宽高的minWidth,maxWidth,minHeight,maxHeight; 示例 Container( constraints: BoxConstraints(0, 0, 100, 100), child: Text("你好"), ); 用法 BoxConstraints.tight(Size(width, height)) 严格

tianhongfan10106的专栏 4710

200smart 模拟量转换库的建立

模拟量当前值 =(工程值 - 工程量下限)*(模拟量上限 - 模拟量下限)/ (工程量上限 - 工程量下限)+ 模拟量下限2. 建立变量表3. 程序。

mmxxoo_xxmmp的博客 4219

Flutter笔记汇总:布局控件篇

前些年里重学flutter的时候,整理了好多篇Flutter相关的文章,有些文章现在看来,太过基础了,整理得也比较简单。因为现在看着感觉太占整体文章数量了,想删掉算了。但是回头想想,这样浪费了当时整理的心意,索性将比较简单的一些删掉之后汇总成一篇出来吧。

wzj_what_why_how的博客 1133

Kettle安装与使用

Pentaho Data Integration作为一个端对端的数据集成平台,可以对多种数据源进行抽取(Extraction)、加载(Loading)、数据落湖(Data Lake Injection)、对数据进行各种清洗(Cleasing)、转换(Transformation)、混合(Blending),并支持多维联机分析处理(OLAP)和数据挖掘(Data mining)。勺子(spoon.bat/spoon.sh):是一个图形化的界面,可以让我们用图形化的方式开发转换和作业。

jnrjian的博客 1万+

图解说明JLink驱动与目标板电源匹配的关键细节

深入讲解JLink驱动安装及使用过程中,如何正确匹配目标板电源,避免常见通信故障。通过图解方式清晰展示关键连接细节,确保调试稳定可靠,是嵌入式开发中不可或缺的实战经验分享。

weixin_42173218的博客 432

Flutter - 布局原理与约束(constraints)

尺寸限制类容器用于限制容器大小,Flutter中提供了多种这样的容器,如ConstrainedBox、SizedBox、UnconstrainedBox、AspectRatio

a136447572的专栏 1732

智能座舱-语音交互系统

从什么是智能座舱、智能座舱的发展驱动因素、智能座舱的构成要素三个方面梳理我对智能座舱的基础认识之后,为了加深“智能座舱产品入门”课程中语音交互部分知识的理解,我从什么是语音交互、语音交互的底层技术、智能座舱的语音交互等方面,对智能座舱语音交互系统相关的知识进行了梳理与总结。

GUOSA0928的博客 1442

Flutter组件--ConstrainedBox、BoxConstraints、UnconstrainedBox(根据内容自适应控件宽度和高度)

ConstrainedBox、BoxConstraints、UnconstrainedBox(根据内容自适应控件宽度和高度)

eastWind1101的博客 2784

Qt + windows + Linux+QtInstallerFramework打包教程

本文介绍了使用Qt Installer Framework在Windows和Linux系统下打包Qt应用程序的完整教程。Windows部分详细说明了从下载安装框架、配置环境变量、生成release版本,到创建安装包目录结构和修改配置文件的完整流程。Linux部分则重点讲解了环境变量设置、桌面应用配置(.desktop文件)以及两种打包方案:一种使用linuxdeployqt生成AppImage文件,另一种采用类似Windows的安装包方式。教程提供了关键配置文件(config.xml、package.xml

Qt历险记,专注Qt技术,三年医疗设备研发经验,1年机器视觉研发经验,半年柔性传感研发经验。 517

Token 费用爆炸?教你用 Semantic Cache(语义缓存)把 API 成本降低 80%

本文介绍了语义缓存(Semantic Cache)技术在大模型应用中的关键作用。传统Redis缓存基于精确匹配,无法处理用户提问的语义相似性,导致重复调用昂贵的LLM API。语义缓存通过将问题向量化并在向量空间中进行相似度匹配,可识别30%-50%的重复提问,直接返回历史答案。文章详细解析了技术原理(Embedding+向量搜索)、架构设计,并提供了基于Python和ChromaDB的50行核心实现代码。同时指出了生产环境中的三大挑战:阈值设定、隐私保护和多轮对话处理,并给出相应解决方案。该技术能以极低成

BUG猿的博客 1056

Flutter布局指南之深入理解BoxConstraints

点击上方蓝字关注我,知识会给你力量强烈建议先看下这篇文章——Flutter你竟是这样的布局不管你是Android开发,还是Flutter开发,当你开始使用Flutter茫茫多的Widget...

eclipse_xu 2287

nvidia jetson orin调试 MAX96712 serdes相机(SG2-AR0233C-GMSL2)

背景:想了解一下关于nvidia orin camera相关的模块,基于Drive Orin demo板的话,没有合适的相机,用 nvsipl框架点亮 GMSL相机不知如何下手,那么基于nvidia Jetson orin的话,目前国内有对应的转接板以及GMSL相机可以参考,基于此,那么本文详细记录一下关于nvidia orin的相关踩坑记录;需要Nvidia Jetson Orin开发板一个,MIPI转接板一个,MIPI转GMSL转接板一个,GMSL线束(fakra单线束),GMSL摄像头一个。

qq_30025621的博客 4447

androidstudio重置页面布局_总结了30个例子之后,我悟到了Flutter的布局原理

总结了30个例子之后,我悟到了Flutter的布局原理学习最忌盲目,无计划,零碎的知识点无法串成系统。学到哪,忘到哪,面试想不起来。这里我整理了Flutter面试中最常问以及Flutter framework中最核心的几块知识,大概二十篇左右文章分析,欢迎关注,共同进步。 Flutter framework.png导语UI原理部分:1、为什么不建议大家使用setState()。2、面试官问我Sta...

weixin_39746382的博客 198

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

通过例子掌握Flutter的布局原理

1、Widget大概可以分为三类组合类、代理类、绘制类2、所有我们在屏幕上看到的UI最终几乎都会通过实现。而中有个方法生成对象,实际负责实际的layout()和paint()。3、Container组件其实只是一个组合类的控件,在其中封装了多个负责绘制的原子组件。4、layout()职能主要是计算控件自身的尺寸和位置偏移5、整个布局过程就是向下约束向上传值的过程tight(紧约束):当max和min值相等时,这时传递给子类的是一个确定的宽高值。...

Dream It Possible 1290

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Flutter布局分析

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。最后针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》

onghaha的博客 1100

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

必读 | 深入理解 Flutter 的布局约束

前言 本文最初来自于社区成员 Marcelo Glasberg 在 Medium 发表的文章——"初学者应知应会的 Flutter 高级布局规则 (Flutter: The Advanced Layout Rule Even Beginners Must Know)",然后被 Flutter Team 发现并收录到 Flutter 官方文档,后经中文社区成员翻译发布至 Flutter 中文文档网站,如果您对本文有任何建议和讨论,请点击阅读原文到 GitHub Issue 中反馈。 在认真

Flutter 社区 3505

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】

布局 Flex布局 Flutter中的Flex布局和Web的Css类似。 在Flutter 中用于控制Flex布局的有Row,Column,Expanded,Flexible,Spacer,Flex这些控件。 row水平布局 属性名 类型 默认值 说明 mainAxisAlignment MainAxisAlignment MainAxisAlignment.start 主轴的排...

qq_43216045的博客 2775

flutter 专题十三 Fair下发产物-布局DSL生成原理

详述具体流程之前,我们先来看看整体的流程,然后再去讲解各个流程的原理细节。通过fair_ast_gen将源码解析并生成AstMap;通过fair_dsl_gen将AstMap转换成我们需要的Fair DSL。这里涉及到两个概念,大家需要先了解一下AST 全称是Abstract Syntax Tree,中文名为抽象语法树。DSL 全称是Domain Specific Language,中文名为领域特定语言。

m0_61164038的博客 945

Flutter (六) Widget布局

Widget布局 布局类Widget都会包含一个或多个子widget,不同的布局类Widget对子widget排版(layout)方式不同。widget其实就是Element的配置数据。Flutter中,根据Widget是否需要包含子节点将Widget分为了三类,分别对应三种Element,如下表: 布局类Widget就是指直接或间接继承(包含)MultiChildRenderObjectWid...

没有翅膀的我们,只是随便认为不能飞而已 535

Flutter 布局真经,小白看完都会了

“OK,那我想要。

533

一文彻底理解Flutter布局约束

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。【Android思维脑图(技能树)】知识不体系?

2301_79058522的博客 1064

【译】Flutter _ 深入理解布局约束

在这里小编整理了一份Android大厂常见面试题,和一些Android架构视频解析,都已整理成文档,全部都已打包好了,希望能够对大家有所帮助,在面试中能顺利通过。喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!源码讲义、实战项目、讲解视频,并且会持续更新!**如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

2401_84123056的博客 1146

Flutter布局核心原理详解

Flutter布局流程遵循"约束向下,尺寸向上"的原则。父组件首先向子组件传递布局约束(如最大宽高),子组件在约束范围内决定自身尺寸后返回给父组件,最后由父组件确定子组件的位置。典型流程包括:1)父组件传递约束;2)子组件选择合适尺寸;3)父组件进行定位。例如,父Container设置400×300的约束,子Container在约束内选择200×150的尺寸,父组件再将其居中显示。这种双向数据流机制确保了灵活而精确的布局控制。

yueke06442300的专栏 453
上一篇: 怎样让你更快的完成工作去“摸鱼”
下一篇: 五年换了三份工作,28岁Android开发一直苦寻属于自己的归属
懂你的大海
博客等级 码龄6年 9049粉丝 1381原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值