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

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);
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB | 绘图复刻(九) | 泰勒图及组合泰勒图

有粉丝问我这个图咋画&#xff1a; 我一看&#xff0c;这不就泰勒图嘛&#xff0c;就fileexchange上搜了一下泰勒图绘制代码&#xff0c;但是有的代码比较新的版本运行要改很多地方&#xff0c;有的代码需要包含一些压缩包没并没有的别人写的函数&#xff0c;于是我干脆自己写了…

【MySQL 数据库】11、学习 MySQL 中的【锁】

目录 一、锁的概述与分类二、全局锁&#xff08;全库数据备份&#xff09;三、表级锁(1) 表锁(2) 元数据锁&#xff08;Meta Data Lock&#xff09;(3) 意向锁 四、行级锁(1) 行锁(2) 间隙锁&临键锁 一、锁的概述与分类 锁是计算机协调多个进程或线程并发访问某一资源的机…

国产Gauss 分布式数据库概述

一、前言 GaussDB 是华为2023年6月7日发布新一代分布式数据库&#xff0c;采用share-nothing架构&#xff0c;数据自动分片&#xff0c;通过GTM-Lite技术实现事务强一致&#xff0c;无中心节点性能瓶颈&#xff0c;是华为基于openGauss自主创新研发的一款分布式关系型数据库&am…

STM32CubeMX | 44 - 使用GPIO点亮单总线RGBLED

一、单总线RGBLED 1. 硬件连接 在DragonFly上有四个全彩灯相连: 其中RGB_LED连接到STM32的PB9引脚。 2. 单总线通信协议 单总线通信协议中,表示bit0和bit1的码型如下: 时序值如下: 驱动一个单总线RGBLED只需要传输24bit颜色数据即可(MSB,高位优先),格式如下(注意…

C++设计模式 - 创建型模式之工厂模式

文章目录 C设计模式 - 创建型模式之工厂模式接口和针对接口编程 1. 简单工厂模式适用场合UML代码示例 2. 工厂方法模式适用场合UML代码示例 3. 抽象工厂模式适用场合UML代码示例 总结 C设计模式 - 创建型模式之工厂模式 工厂模式属于创建型模式&#xff0c;大致可以分为三类&a…

力扣 209. 长度最小的子数组

一、题目描述 给定一个含有 n 个正整数的数组和一个正整数 target。 找出该数组中满足其和大于等于 target 的长度最小的连续子数组&#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0。 示例 1&#xff1a; 输入&#xff1a;target 7, nums [2,3,1…

Uni-app学习从0到1开发一个app——(3)简单小工程内容介绍

文章目录 工程文件 看看一个标准的hello微信小程序工程文件的组成和作用。 工程文件 可以参考官方教程&#xff1a;传送门 之前的文章有详细的开发环境介绍&#xff0c;传送门Uni-app学习从0到1开发一个app——(2)windowns环境搭配&#xff0c;这里我们先建一个简单的示例微信…

C++教程(06)——变量类型

C 变量类型 变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有指定的类型&#xff0c;类型决定了变量存储的大小和布局&#xff0c;该范围内的值都可以存储在内存中&#xff0c;运算符可应用于变量上。 变量的名称可以由字母、数字和下划线字符组成。它必须以字母…

华为OD机试真题B卷 Java 实现【自守数】,附详细解题思路

一、题目描述 自守数是指一个数的平方的尾数等于该数自身的自然数。例如&#xff1a;252 625&#xff0c;762 5776&#xff0c;93762 87909376。 请求出n(包括n)以内的自守数的个数。 数据范围&#xff1a; 1≤n≤10000 二、输入描述 int型整数。 三、输出描述 n以内…

大话Stable-Diffusion-Webui-动手开发一个简单的stable-diffusion-webui(一)

文章目录 写在前面整体效果开发所需环境开发工具需要具备的知识Node安装更改npm包安装的目录设置npm镜像vscode安装创建vue项目代码编写项目先体验注意写在前面 stable-diffusion-webui(以下简称sd)项目通过FastAPI对外提供了一系列的api用于开发者二次开发或者集成到自己的…

005Mybatis返回值(ResultMap 一对多,多对多)

属性 id 应该总是指定一个或多个可以唯一标识结果的属性。 虽然&#xff0c;即使不指定这个属性&#xff0c;MyBatis 仍然可以工作&#xff0c;但是会产生严重的性能问题。 只需要指定可以唯一标识结果的最少属性。显然&#xff0c;你可以选择主键&#xff08;复合主键也可以…

MixQuery系列(一):多数据源混合查询引擎调研

背景 存储情况 当前的存储引擎可谓百花齐放,层出不穷。为什么会这样了?因为不存在One for all的存储,不同的存储总有不同的存储的优劣和适用场景。因此,在实际的业务场景中,不同特点的数据会存储到不同的存储引擎里。 业务挑战 然而异构的存储和数据源,却给分析查询带…

Vue中如何进行状态持久化(LocalStorage、SessionStorage)

Vue中如何进行状态持久化&#xff08;LocalStorage、SessionStorage&#xff09;&#xff1f; 在Vue应用中&#xff0c;通常需要将一些状态进行持久化&#xff0c;以便在用户关闭浏览器或刷新页面后&#xff0c;仍能保留之前的状态。常见的持久化方式包括LocalStorage和Sessio…

【软件环境安装部署】华为云服务器下 Docker 安装 MongoDB 以及 SpringBoot 整合 MongoDB 开发使用

文章目录 安装测试 MongoDB拉取镜像创建和启动容器登录mongo容器&#xff0c;并进入到【admin】数据库创建一个用户&#xff0c;mongo 默认没有用户连接mongo数据库测试数据库&#xff0c;插入一条语句测试数据库&#xff0c;查询刚才插入的语句查看所有数据库开放指定端口开放…

华为存储IA篇仿真器搭建

设备清单 编号 设备名 数量 备注 01 Windows系统主机 1台 为VMware提供安装位置 02 VMware软件 1份 提供存储仿真器的部署环境 03 仿真器文件 1份 用于部署estor虚拟机 【注意】&#xff1a;暂无注意事项 一、下载安装文件并配置虚拟机设备清单 1.1…

动态测试数据处理

分类 动态测试数据&#xff1a; 1、确定性数据&#xff1a;能够用明确的数学表达式进行描述的数据称为确定性数据。 Ⅰ、周期数据 Ⅱ、非周期数据 2、随机性数据&#xff1a;无法用明确的数学表达式表述&#xff1b;若在一个…

Qt详解实现TCP文件传输例子(文件下载和上传)附源码

网络通信我们用的很频繁&#xff0c;如文字&#xff0c;语音&#xff0c;文件&#xff0c;图片等&#xff0c;这个些传输方式都差不多 QT文件传输主要考验对传输的控制&#xff0c;还是需要点逻辑的&#xff0c;文件传输的大致框架如下 先看一下简单例子实现的效果&#xff08…

【伏羲八卦图】(PythonMatlab实现)

目录 1 与达尔文对话 2 与老子对话 2.1 Python实现 2.2 Matlab实现 1 与达尔文对话 140年前&#xff0c;1858年7月1日&#xff0c;达尔文在英伦岛发表了自己有关自然选择的杰出论文。他提出&#xff0c;生物的发展规律是物竞天择。经过物竞&#xff0c;自然界选择并存留最具…

k8s实践之mysql集群搭建(十五)

先下载 k8s实践之mysql集群搭建资料 主从模式简介&#xff1a; 当master主服务器上的数据发生改变时&#xff0c;则将其改变写入二进制&#xff08;binlog&#xff09;事件日志文件中&#xff1b; slave从服务器会在一定时间间隔内对master主服务器上的二进制日志进行探测&am…

【算法题解】38. 括号的生成

这是一道 中等难度 的题 https://leetcode.cn/problems/generate-parentheses/ 题目 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["…