Flutter(四)布局类组件
目录
- 布局类组件简介
- 布局原理与约束
- 线性布局(Row和Column)
- 弹性布局
- 流式布局(Wrap、Flow)
- 层叠布局(Stack、Positioned)
- 对齐与相对定位(Align)
- Align和Stack对比
- Center组件
- LayoutBuilder、AfterLayout
- LayoutBuilder
- AfterLayout
布局类组件简介
布局类组件就是指直接或间接继承(包含)SingleChildRenderObjectWidget 和MultiChildRenderObjectWidget的Widget
它们一般都会有一个child或children属性用于接收子 Widget。
继承关系 Widget > RenderObjectWidget > (Leaf/SingleChild/MultiChild)RenderObjectWidget
RenderObjectWidget类中定义了创建、更新RenderObject的方法,子类必须实现他们
RenderObject:渲染UI界面的
布局原理与约束
BoxConstraints 是盒模型布局过程中父渲染对象传递给子渲染对象的约束信息,包含最大宽高信息,子组件大小需要在约束的范围内
const BoxConstraints({this.minWidth = 0.0, //最小宽度this.maxWidth = double.infinity, //最大宽度this.minHeight = 0.0, //最小高度this.maxHeight = double.infinity //最大高度
})
ConstrainedBox用于对子组件添加额外的约束
Widget redBox = DecoratedBox(decoration: BoxDecoration(color: Colors.red),
);ConstrainedBox(constraints: BoxConstraints(minWidth: double.infinity, //宽度尽可能大minHeight: 50.0 //最小高度为50像素),child: Container(height: 5.0, child: redBox ,),
)
SizedBox用于给子元素指定固定的宽高
SizedBox(width: 80.0,height: 80.0,child: redBox
)
任何时候子组件都必须遵守其父组件的约束,如果我们需要自定义约束必须通过UnconstrainedBox来 “去除” 父元素的限制
线性布局(Row和Column)
Row和Column都继承自Flex,类似Android 中的LinearLayout
线性布局有主轴和纵轴之分,
如果布局沿水平方向,那么主轴就是指水平方向,而纵轴即垂直方向
如果布局沿垂直方向,那么主轴就是指垂直方向,而纵轴就是水平方向
Row:水平
Column:垂直
//Row和Column的属性Key? key,MainAxisAlignment//主轴对齐方式//默认MainAxisSize.max:占满宽度,类似match_parent//MainAxisSize.min:子组件的宽度总和,类似wrap_contentMainAxisSizeCrossAxisAlignment //纵轴对齐方式TextDirection //从左往右还是从右往左排列,默认从左往右VerticalDirection//纵轴对齐方向TextBaseline//对齐文本的水平线List<Widget> children = const <Widget>[] //子组件数组
如果Row里面嵌套Row,或者Column里面再嵌套Column,那么只有最外面的Row或Column会占用尽可能大的空间,里面Row或Column所占用的空间为实际大小,如果要让里面的Column占满外部Column,可以使用Expanded 组件
弹性布局
弹性布局允许子组件按照一定比例来分配父容器空间,Flutter 中的弹性布局主要通过Flex和Expanded来配合实现
Flex({...required this.direction, //弹性布局的方向, Row默认为水平方向,Column默认为垂直方向List<Widget> children = const <Widget>[],
})
const Expanded({int flex = 1, //比例系数,类似LinearLayout中的layout_weightrequired Widget child,
})
流式布局(Wrap、Flow)
Row 和 Colum ,如果子 widget 超出屏幕范围,则会报溢出错误
流式布局含义:超出屏幕自动换行
Flutter中通过Wrap和Flow来支持流式布局
Wrap({...spacing//主轴方向子widget的间距runSpacing//纵轴方向子widget的间距runAlignment//纵轴方向的对齐方式
})
Flow:Flow很少用,因为过于复杂,需要自己实现子 widget 的位置转换,在很多场景下首先要考虑的是Wrap是否满足需求。Flow主要用于一些需要自定义布局策略或性能要求较高(如动画中)的场景
Flow不能自适应子widget的大小,我们通过在getSize返回一个固定大小来指定Flow的大小
层叠布局(Stack、Positioned)
类似Android 中的 Frame,Flutter中使用Stack和Positioned这两个组件来配合实现绝对定位
Stack({this.alignment = AlignmentDirectional.topStart,//对齐方式this.textDirection,//子组件排列顺序,默认从左往右//此参数用于确定没有定位的子组件如何去适应Stack的大小。//StackFit.loose表示使用子组件的大小,//StackFit.expand表示扩伸到Stack的大小。this.fit = StackFit.loose,//此属性决定对超出Stack显示空间的部分如何剪裁,//Clip枚举类中定义了剪裁的方式,Clip.hardEdge 表示直接剪裁...this.clipBehavior = Clip.hardEdge,List<Widget> children = const <Widget>[],
})
//left、top 、right、 bottom分别代表离Stack左、上、右、底四边的距离
//width和height用于指定需要定位元素的宽度和高度
const Positioned({Key? key,this.left, this.top,this.right,this.bottom,this.width,this.height,required Widget child,
})
对齐与相对定位(Align)
如果我们只想简单的调整一个子元素在父元素中的位置的话,使用Align组件会更简单一些
Align({Key key,this.alignment = Alignment.center,//子组件在父组件中的起始位置this.widthFactor,//会分别乘以子元素的宽、高,最终的结果就是Align 组件的宽高this.heightFactor,//会分别乘以子元素的宽、高,最终的结果就是Align 组件的宽高Widget child,
})
//因为FlutterLogo的宽高为 60,则Align的最终宽高都为2*60=120。
Align(widthFactor: 2,heightFactor: 2,alignment: Alignment.topRight,child: FlutterLogo(size: 60,),
),
Alignment可以通过其坐标转换公式将其坐标转为子元素的具体偏移坐标:
(Alignment.x*childWidth/2+childWidth/2, Alignment.y*childHeight/2+childHeight/2)
FractionalOffset 继承自 Alignment,它和 Alignment唯一的区别就是坐标原点不同!FractionalOffset 的坐标原点为矩形的左侧顶点,FractionalOffset的坐标转换公式为:
实际偏移 = (FractionalOffse.x * childWidth, FractionalOffse.y * childHeight)
Align和Stack对比
Stack/Positioned定位的的参考系可以是父容器矩形的四个顶点;而Align则需要先通过alignment 参数来确定坐标原点.
Stack可以有多个子元素,并且子元素可以堆叠,而Align只能有一个子元素,不存在堆叠
Center组件
Center继承自Align,它比Align只少了一个alignment 参数
Center(widthFactor: 1,heightFactor: 1,child: Text("xxx"),),
LayoutBuilder、AfterLayout
LayoutBuilder
通过 LayoutBuilder,我们可以在布局过程中拿到父组件传递的约束信息,然后我们可以根据约束信息动态的构建不同的布局。
它主要有两个使用场景:
- 可以使用 LayoutBuilder 来根据设备的尺寸来实现响应式布局。
- LayoutBuilder 可以帮我们高效排查问题。比如我们在遇到布局问题或者想调试组件树中某一个节点布局的约束时 LayoutBuilder 就很有用
为了便于排错,我们封装一个能打印父组件传递给子组件约束的组件:
class LayoutLogPrint<T> extends StatelessWidget {const LayoutLogPrint({Key? key,this.tag,required this.child,}) : super(key: key);final Widget child;final T? tag; //指定日志tag@overrideWidget build(BuildContext context) {return LayoutBuilder(builder: (_, constraints) {// assert在编译release版本时会被去除assert(() {print('${tag ?? key ?? child}: $constraints');return true;}());return child;});}
}
我们就可以使用 LayoutLogPrint 组件树中任意位置的约束信息,比如:
LayoutLogPrint(child:Text("xx"))
控制台输出:
flutter: Text("xx"): BoxConstraints(0.0<=w<=428.0, 0.0<=h<=823.0)
可以看到 Text(“xx”) 的显示空间最大宽度为 428,最大高度为 823 。
我们的大前提是盒模型布局,如果是Sliver 布局,可以使用 SliverLayoutBuiler 来打印。
AfterLayout
- 布局一结束就去获取大小和位置信息,笔者封装了一个 AfterLayout 组件,它可以在子组件布局完成后执行一个回调,并同时将 RenderObject 对象作为参数传递。
AfterLayout(callback: (RenderAfterLayout ral) {print(ral.size); //子组件的大小print(ral.offset);// 子组件在屏幕中坐标},child: Text('flutter@wendux'),
),
控制台输出:
flutter: Size(105.0, 17.0)
flutter: Offset(42.5, 290.0)
Text 文本的实际长度是 105,高度是 17,它的起始位置坐标是(42.5, 290.0)
- 获取组件相对于某个父组件的坐标
RenderAfterLayout 类继承自 RenderBox,RenderBox 有一个 localToGlobal 方法,它可以将坐标转化为相对与指定的祖先节点的坐标,比如下面代码可以打印出 Text(‘A’) 在 父 Container 中的坐标
Builder(builder: (context) {return Container(color: Colors.grey.shade200,alignment: Alignment.center,width: 100,height: 100,child: AfterLayout(callback: (RenderAfterLayout ral) {Offset offset = ral.localToGlobal(Offset.zero,// 传一个父级元素ancestor: context.findRenderObject(),);print('A 在 Container 中占用的空间范围为:${offset & ral.size}');},child: Text('A'),),);
}),
通过观察 LayoutBuilder 的示例,我们还可以发现一个关于 Flutter 构建(build)和 布局(layout)的结论:Flutter 的build 和 layout 是可以交错执行的,并不是严格的按照先 build 再 layout 的顺序
至此,布局类组件完结。
相关文章:
Flutter(四)布局类组件
目录布局类组件简介布局原理与约束线性布局(Row和Column)弹性布局流式布局(Wrap、Flow)层叠布局(Stack、Positioned)对齐与相对定位(Align)Align和Stack对比Center组件LayoutBuilder…...
【黑马】Java基础从入门到起飞目录合集
视频链接: Java入门到起飞(上部):BV17F411T7AoJava入门到起飞(下部):BV1yW4y1Y7Ms 学习时间: 2023/02/01 —— 2023/03/09断断续续的学习,历时大概37天,完结撒…...
PMP考前冲刺3.10 | 2023新征程,一举拿证
题目1-2:1.在最近的一次耗时四周的迭代中,赫克托尔所在的敏捷团队刚完成了10 个用户故事点的开发、测试和发布,那么团队的速度是?A. 10B. 4C. 5D.402.产品负责人奥佩,倾向于在短周期内看到工作产品的新版本,…...
JavaScript Math常用方法
math是JavaScript的一个内置对象,它提供了一些数学属性和方法,可以对数字进行计算(用于Number类型)。 math和其他全局对象不同,它不是一个构造器,math的所有方法和属性都是静态的,直接使用并传入…...
【C++】模板进阶
文章目录一、非类型模板参数1、非类型模板参数2、C11 中的 array 类二、模板的特化1、模板特化的概念2、函数模板特化3、类模板特化3.1 全特化3.2 偏特化三、模板的分离编译四、模板总结一、非类型模板参数 1、非类型模板参数 模板参数分为类型形参与非类型形参,类…...
三板斧解决leetcode的链表题
在《波奇学单链表》中我们提到单链表的两个特点单向性。头节点尾节点的特殊性导致分类讨论的情况。如何看单链表?让我们简化成下图cur表示当前节点,下图表示cur移动,圆圈表示值用哨兵卫节点(新的头节点)和把尾节点看成NULL来把头尾节点一般化…...
全生命周期的云原生安全框架
本博客地址:https://security.blog.csdn.net/article/details/129423036 一、全生命周期的云原生安全框架 如图所示: 二、框架说明 在上图中,我们从两个维度描述各个安全机制,横轴是开发和运营阶段,细分为编码、测试…...
【本地网站上线】ubuntu搭建web站点,并内网穿透发布公网访问
【本地网站上线】ubuntu搭建web站点,并内网穿透发布公网访问前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar3.2 创建隧道3.3 测试公网访问4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子…...
电脑怎么重装系统?教你轻松掌握这些方法
重新安装计算机系统有两种原因:一种是计算机系统可以正常使用,但是电脑比较卡,为了提高它的运行速度,所以想要通过重新安装系统来解决这个问题;另一种原因是计算机系统文件丢失,系统出现蓝屏,或者黑屏的情况…...
leetcode-每日一题-2379(简单,字符串)
久违的简单题......给你一个长度为 n 下标从 0 开始的字符串 blocks ,blocks[i] 要么是 W 要么是 B ,表示第 i 块的颜色。字符 W 和 B 分别表示白色和黑色。给你一个整数 k ,表示想要 连续 黑色块的数目。每一次操作中,你可以选择…...
SLF4J日志框架在项目中使用
介绍 SLF4J全称“Simple Logging Facade for Java”,作为各种日志框架的简单门面。例如: java.util.logging、logback 、 reload4j等。只需要切换日志框架的jar包依赖就可以切换日志框架。 SLF4J支持的日志框架包含如下: log4j:…...
Spark MLlib 模型训练
Spark MLlib 模型训练决策树随机森林GBDTSpark MLlib 开发框架下 : 监督学习 : 回归 (Regression) , 分类 (Classification) , 协同过滤 (Collaborative Filtering)非监督学习 : 聚类 (Clustering) 、频繁项集 (Frequency Patterns) 例子分类 : 算法分类 : 算法分类算法子分类…...
Python中变量的作用域精讲
文章目录前言一、局部变量二、全局变量前言 变量的作用域是指程序代码能够访问该变量的区域,如果超出该区域,再访问时就会出现错误。在程序中,一般会根据变量的 “有效范围” 将变量分为 “全局变量” 和 “局部变量”。 一、局部变量 局部变…...
数据仓库工程师的工作职责的相关介绍
1. BI 开发工程师的工作内容是什么? BI开发工程师(Business Intelligence Developer)是负责设计和开发企业级BI系统的专业人员。他们的主要工作是从多个数据源中提取、转换、加载和分析数据,以支持企业决策。以下是BI开发工程师的…...
ESP UART 介绍
1 UART 介绍 UART 是一种以字符为导向的通用数据链,可以实现设备间的通信。异步传输的意思是不需要在发送数据上添加时钟信息。这也要求发送端和接收端的速率、停止位、奇偶校验位等都要相同,通信才能成功。 1.1 UART 通信协议 一个典型的 UART 帧开始…...
第十三届蓝桥杯省赛Python大学B组复盘
目录 一、试题B:寻找整数 1、题目描述 2、我的想法 3、官方题解 4、另解 二、试题E:蜂巢 1、题目描述 2、我的想法 3、官方题解 三、试题F:消除游戏 1、题目描述 2、我的想法(AC掉58.3%,剩下全超时&#x…...
linux入门---vim的配置
这里写目录标题预备知识如何配置vimvim一键配置预备知识 在配置vim之前大家首先得知道一件事就是vim的配置是一人一份的,每个用户配置的vim都是自己的vim,不会影响到其他人,比如说用户xbb配置的vim是不会影响到用户wj的,虽然不同…...
Python简写操作(for、if简写、匿名函数)
Python简写操作(for、if简写、匿名函数)1. for 简写1.1 一层 for 循环1.2 两层 for 循环2. if 简写3. for 与 if 的结合简写4. 匿名函数 lambda1. for 简写 举个例子: y [1, 2, 3, 4, 5, 6] result [(i * 2) for i in y] print(result)# …...
毕业设计常用模块之温湿度模块DHT11模块使用
DHT11是一款可以测量温度数据和湿度数据的传感器 产品特点 暖通空调、除湿器、农业、冷链仓储、测试及检测设备、消费品、汽车、自动控制、数据记录器、气 象站、家电、湿度调节器、医疗、其他相关湿度检测控制 外形尺寸 第3管脚:NC 是没有用的 典型电路 通信方式…...
Cadence Allegro 导出Design Rules Net Shorts Check(DRC)Report报告详解
⏪《上一篇》 🏡《上级目录》 ⏩《下一篇》 目录 1,概述2,Design Rules Net Shorts Check(DRC)Report作用3,Design Rules Net Shorts Check(DRC)Report示例4,Design Rules Net Shorts Check(DRC)Report导出方法4.1,方法14.2,方法2...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
