Flutter进阶篇-布局(Layout)原理

news2025/4/15 13:15:10

1、约束、尺寸、位置  

  @override
  Widget build(BuildContext context) {
    return Scaffold(body: LayoutBuilder(builder: (context, constraints) {
      print("body约束:" + constraints.toString());
      return Container(
          color: Colors.black,
          width: 300,
          height: 300,
          child: LayoutBuilder(builder: (context, constraints) {
            print("Container约束:" + constraints.toString());
            return Container(width: 20, height: 20, color: Colors.orange);
          }));
    }));
  }

运行效果图: 

控制台输出:

flutter: body约束:BoxConstraints(0.0<=w<=390.0, 0.0<=h<=844.0)
flutter: Container约束:BoxConstraints(w=300.0, h=300.0)

由此得出结论:

  • body对子控件是loose松约束(子控件可以设置指定宽高);
  • Container对子控件是tight强约束(如果子控件不指定位置怎么摆放的话,因为不指定位置的话系统也不知道子控件放大或者缩小后该怎么摆放,索性填充满父控件,设置宽高自然会失效),本质上是子控件违背了父控件的约束,所以一律按照父控件约束执行
  • 总结:当设置子控件大小的时候如果不听使唤可以用LayoutBuilder(builder: (context, constraints){})打印下看看是tight还是loose

布局原理:

每个组件在渲染之前的布局过程具体可分为两个线性过程。首先从组件顶部向下传递布局约束,然后从底部向上传递布局信息。

简单点说就是flutter在布局的时候会遍历组件树 ,从根部开始(deep first 深度优先原则)向下传递约束,当子控件约束违背父控件约束的时候会执行父控件约束。flutter的布局是onePass只需要遍历WidgetTree一遍,向上传递尺寸,最后由父级得到尺寸再决定把children放在哪里

这两个线性过程会在元素树所引用的RenderObject树中完成,并且最终的布局信息将保存在RenderObject中。因此,当重新构建组件时,如果元素和RenderObject能够复用,那么同样可以使用和上次一样的布局信息。这种单向传递和保存信息的方式是Flutter布局性能优于其他框架的重要原因之一。

RenderObject树由一个个RenderObject组合而成。当Element实例挂载到元素树上后,就会调用组件的createRenderObject()方法生成对应的RenderObject。由于RenderObject树被元素树引用,并且主要任务就是帮助Element实例做具体的渲染工作,因此RenderObject树也常称为元素树的子树。

 每个RenderObject会被元素持有,并且在组件重建后会尽量复用,每当元素中的状态发生改变时,就会调用组件的updateRenderObject()方法更新渲染对象,屏幕上的值最终得以更新。

2、自定义盒子布局约束

 @override
  Widget build(BuildContext context) {
    return Scaffold(body: LayoutBuilder(builder: (context, constraints) {
      print("body约束:" + constraints.toString());
      return Container(
        constraints: BoxConstraints(
            minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100),
        child: LayoutBuilder(builder: (context, constraints) {
          print("Container约束:" + constraints.toString());
          return FlutterLogo(size: 500);
        }),
      );
    }));
  }

flutter: body约束:BoxConstraints(0.0<=w<=390.0, 0.0<=h<=844.0)
flutter: Container约束:BoxConstraints(60.0<=w<=100.0, 60.0<=h<=100.0)

3.Stack层叠组件

  1. (children里既有普通Widget又有Position包裹的Widget),其大小是由children中没有被Position包裹的Widget中的最大个子组件决定,(被Position包裹的子组件有点类似于前端布局中的absolute绝对布局会脱离文档流)可以超出父组件显示,不想显示也可以设置clipBehavior: Clip.hardEdge,强制裁剪超出部分。
  2. (children里全部是普通的Widget),其大小是包裹着子组件
  3. children里全部是Position包裹的Widget,就没有参照物不知道该怎么布局)Stack的大小会充满父组件尽可能的大,(因为只有Stack自身足够大对应的children设置左上对齐或者其他对齐才会有意义,不然会挤在一起失去了原有设置对齐的意义)

4、CustomMultiChildLayout

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: CustomMultiChildLayout(
      delegate: MyDelegate(4),
      children: [
        LayoutId(
            id: "text",
            child: Text(
                "测试文字下划线测试文字下划线测试文字下划线测试文字下划线测试文字下划线测试文字下划线测试文字下划线测试文字下划线")),
        LayoutId(
            id: "underline",
            child: Container(
              color: Colors.green,
            ))
      ],
    ));
  }

class MyDelegate extends MultiChildLayoutDelegate {

final double thickness;

MyDelegate(this.thickness);



@override

Size getSize(BoxConstraints constraints) {

return super.getSize(constraints);

}

@override

void performLayout(Size size) {

final sizeText = layoutChild("text", BoxConstraints.loose(size));



final sizeUnderline =

layoutChild("underline", BoxConstraints.tight(Size(sizeText.width, thickness)));



final left = (size.width - sizeText.width) / 2;

final top = (size.height - sizeText.height) / 2;

positionChild("text", Offset(left, top));

positionChild("underline", Offset(left, top + sizeText.height));

}



@override

bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) => true;

}

 5、RenderObject

 @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
            color: Colors.red,
            child: ShadowBox(child: FlutterLogo(size: 200), distance: 200)));
  }


//SingleChildRenderObjectWidget一种能真正画到屏幕上的widget
class ShadowBox extends SingleChildRenderObjectWidget {
  double distance;
  ShadowBox({Widget child, this.distance}) : super(child: child);

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

  @override
  void updateRenderObject(
      BuildContext context, covariant RenderShadowBox renderObject) {
    renderObject.distance = distance;
  }
}

//RenderObjectWithChildMixin比较方便的设置一个child
class RenderShadowBox extends RenderProxyBox with DebugOverflowIndicatorMixin {
  double distance;

  RenderShadowBox(this.distance);

  //处理布局
  // @override
  // void performLayout() {
  //   child.layout(constraints, parentUsesSize: true); //parentUsesSize: false
  //   // 如果parentUsesSize: false则parent的size跟这个child没关系以后再relayout凡是涉及到这个child的不会再更新,如果是true则代表会使用这个child
  //   size = (child as RenderBox).size; // relayout boundary
  //   // size = Size(300, 100);
  // }

  //处理绘制
  //其实layout和paint各遍历一次
  @override
  void paint(PaintingContext context, Offset offset) {
    context.paintChild(child, offset);
    context.canvas.clipRRect(RRect.fromLTRBAndCorners(105, 5, 5, 5));
    //建立新图层,可以在新图层上做各种操作
    context.pushOpacity(offset, 100, (context, offset) {
      context.paintChild(child, offset + Offset(distance, distance));
    });
    //containerRect: 能画的范围
    //childRect: 想让画的范围
    //警戒线
    paintOverflowIndicator(
        context,
        offset,
        Offset.zero & size, //Rect.fromLTWH(0, 0, size.width, size.height)
        Offset.zero & child.size);
  }
}

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

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

相关文章

【企业化架构部署】基于Nginx搭建LNMP架构

文章目录 一、安装 MySQL 数据库1. 安装Mysql环境依赖包2. 创建运行用户3. 编译安装4. 修改mysql 配置文件5. 更改mysql安装目录和配置文件的属主属组6. 设置路径环境变量7. 初始化数据库8. 添加mysqld系统服务9. 修改mysql 的登录密码10. 授权远程登录 二、编译安装 nginx 服务…

Maven 工具

Maven 工具 Maven简介Maven 基础概念创建 Maven项目依赖配置生命周期与插件分模块开发聚合和继承聚合继承聚合与继承的区别 属性版本管理多环境配置与应用私服 Maven简介 Maven 本质是一个项目管理工具&#xff0c;将项目开发和管理过程抽象成一个项目对象模型&#xff08;POM…

【爬虫】3.4爬取网站复杂数据

1. Web服务器网站 进一步把前面的Web网站的mysql.html, python.html, java.html丰富其中 的内容&#xff0c;并加上图形&#xff1a; mysql.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>my…

ICV报告: 智能座舱SoC全球市场规模预计2025年突破50亿美元

在智能化、互联化车辆需求不断增加的推动下&#xff0c;汽车行业正在经历一场范式转变。这一转变的前沿之一是智能座舱SoC。本市场研究报告对智能座舱SoC市场进行了全面的分析&#xff0c;包括其应用领域、当前状况和主要行业参与者。 智能座舱SoC指的是现代汽车智能座舱系统的…

Qt6.5.1+WebRTC学习笔记(十)开发环境搭建(win10+vs2022)

一、准备 1.操作系统win10 64位 2.合理的上网方式&#xff0c;需要正常访问google,最好有40G以上流量 3.安装VS2022&#xff0c;笔者使用的是社区版&#xff0c;并选中C相关&#xff0c;笔者设置如下 注意&#xff0c;win10的sdk需要是10.0.22621.0&#xff0c;其他版本可能…

吴恩达 ChatGPT Prompt Engineering for Developers 系列课程笔记--06 Transforming

06 Transforming 大语言模型&#xff08;LLM&#xff09;很擅于将输入转换为不同格式的输出&#xff0c;比如翻译、拼写校正或HTML格式转化。相比于复杂的正则表达式&#xff0c;Chat GPT实现更加准确和高效。 1) 不同语种的转换 下述语句实现了英文到西班牙语的翻译。 pro…

Windows IIS/docker+gunicorn两种方式部署django项目

写在最前 本篇文章并不涉及如何使用宝塔搭建django项目&#xff0c;仅适用于windows和docker部署&#xff0c;其中docker是运行在linux平台上的&#xff0c;如果您想在windows上运行docker&#xff0c;请自行搜索如何在windows上运行docker 一、Windows IIS部署 软件版本Win…

MySQL-Linux版安装

MySQL-Linux版安装 1、准备一台Linux服务器 云服务器或者虚拟机都可以&#xff1b; Linux的版本为 CentOS7&#xff1b; 2、 下载Linux版MySQL安装包 下载地址 3、上传MySQL安装包 使用FinalShell软件上传即可&#xff01; 4、 创建目录,并解压 mkdir mysqltar -xvf my…

【SpringCloud学习笔记】zuul网关

【SpringCloud学习笔记】 为什么需要网关zuul网关搭建zuul网关服务网关过滤器 为什么需要网关 微服务项目一般有多个服务&#xff0c;每个服务的地址都不同&#xff0c;客户端如果直接访问服务&#xff0c;无疑是增加客户端开发难度&#xff0c;项目小还好&#xff0c;如果项目…

【图像任务】Transformer系列.1

介绍几篇改进Transformer模型实现亮度增强、图像重建的任务&#xff1a;LLFormer&#xff08;AAAI2023&#xff09;&#xff0c;DLSN&#xff08;TPAMI2023&#xff09;&#xff0c;CAT&#xff08;NeurIPS2022&#xff09;。 Ultra-High-Definition Low-Light Image Enhanceme…

Linux | 进程控制

啊我摔倒了..有没有人扶我起来学习.... &#x1f471;个人主页&#xff1a; 《 C G o d 的个人主页》 \color{Darkorange}{《CGod的个人主页》} 《CGod的个人主页》交个朋友叭~ &#x1f492;个人社区&#xff1a; 《编程成神技术交流社区》 \color{Darkorange}{《编程成神技术…

Redis的内存策略

过期Key处理: 1)Redis之所以性能强大&#xff0c;最主要的原因就是基于内存来存储&#xff0c;然而单节点的Redis内存不宜设置的过大&#xff0c;否则会影响持久化或者是主从复制的性能&#xff0c;可以通过修改配置文件来设置redis的最大内存&#xff0c;通过maxmemory 1gb&am…

javaScript蓝桥杯-----粒粒皆辛苦

目录 一、介绍二、准备三、目标四、代码五、完成 一、介绍 俗话说“民以食为天”&#xff0c;粮食的收成直接影响着民生问题&#xff0c;通过对农作物产量的统计数据也能分析出诸多实际问题。 接下来就让我们使用 ECharts 图表&#xff0c;完成 X 市近五年来的农作物产量的统…

Python批量下载参考文献|基于Python的Sci-Hub下载脚本|Python批量下载sci-hub文献|如何使用sci-hub批量下载论文

本篇博文将介绍如何通过Python的代码实现快速下载指定DOI号对应的文献&#xff0c;并且使用Sci-Hub作为下载库。 一、库函数准备 在开始之前&#xff0c;我们需要先安装一些必要的库&#xff0c;包括&#xff1a; requests&#xff1a;发送HTTP请求并获取响应的库&#xff1…

南山城市更新--向南村(一期,二期)项目详情

向南村&#xff08;一期&#xff09;城市更新单元项目简介 项目于2010年被列入《深圳城市更新单元规划制定计划第一批计划》中&#xff0c;申报主体为向南实业股份有限公司&#xff0c;后与恒大合作开发。 项目位于南山区桂庙路南侧&#xff0c;毗邻前海、衔接后海&am…

经典算法:Fenwick Tree

经典算法&#xff1a;Fenwick Tree 1. 算法简介2. 原理介绍3. 算法实现4. 例题说明 1. 解题思路2. 代码实现 5. 参考链接 1. 算法简介 Fenwick Tree又称为Binary Indexed Tree&#xff0c;也算是一种常见的数据结构了。 他其实某种意义上来说算是Segment Tree的一种变体&…

克隆虚拟机

上一篇我们已经讲过了启动虚拟机并安装Linux系统&#xff0c;下面我们来讲一下如何通过已经创建好的虚拟机spark01克隆出spark02和spark03来&#xff0c;从而满足搭建大数据集群环境需要多台虚拟机的需求。 首先我们要理解两个概念&#xff1a; 1.完整克隆 完整克隆的虚拟机可…

【算法证明 三】计算顺序统计量的复杂度

计算顺序统计量&#xff0c;在 c 标准库中对应有一个函数&#xff1a;nth_element。其作用是求解一个数组中第 k 大的数字。常见的算法是基于 partition 的分治算法。不难证明这种算法的最坏复杂度是 Θ ( n 2 ) \Theta(n^2) Θ(n2)。但是其期望复杂度是 Θ ( n ) \Theta(n) …

从源码全面解析 dubbo 服务暴露的来龙去脉

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、Spring源码系列、Netty源码系列、Kafka源码系列、JUC源码…

SpringBoot配置 -- SpringBoot快速入门保姆级教程(二)

文章目录 前言二、SpringBoot配置1. 了解配置文件的3种格式2.yaml格式语法规则3.读取yaml数据的3种方式4.多环境开发配置5.多环境命令行启动参数设置6. 多环境开发兼容问题7.配置文件分类 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&am…