当前位置: 首页 > news >正文

Flutter(四)布局类组件

目录

  • 布局类组件简介
  • 布局原理与约束
  • 线性布局(Row和Column)
  • 弹性布局
  • 流式布局(Wrap、Flow)
  • 层叠布局(Stack、Positioned)
  • 对齐与相对定位(Align)
    • Align和Stack对比
    • Center组件
  • LayoutBuilder、AfterLayout
    • LayoutBuilder
    • AfterLayout

布局类组件简介

布局类组件就是指直接或间接继承(包含)SingleChildRenderObjectWidgetMultiChildRenderObjectWidget的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(四)布局类组件

目录布局类组件简介布局原理与约束线性布局&#xff08;Row和Column&#xff09;弹性布局流式布局&#xff08;Wrap、Flow&#xff09;层叠布局&#xff08;Stack、Positioned&#xff09;对齐与相对定位&#xff08;Align&#xff09;Align和Stack对比Center组件LayoutBuilder…...

【黑马】Java基础从入门到起飞目录合集

视频链接&#xff1a; Java入门到起飞&#xff08;上部&#xff09;&#xff1a;BV17F411T7AoJava入门到起飞&#xff08;下部&#xff09;&#xff1a;BV1yW4y1Y7Ms 学习时间&#xff1a; 2023/02/01 —— 2023/03/09断断续续的学习&#xff0c;历时大概37天&#xff0c;完结撒…...

PMP考前冲刺3.10 | 2023新征程,一举拿证

题目1-2&#xff1a;1.在最近的一次耗时四周的迭代中&#xff0c;赫克托尔所在的敏捷团队刚完成了10 个用户故事点的开发、测试和发布&#xff0c;那么团队的速度是&#xff1f;A. 10B. 4C. 5D.402.产品负责人奥佩&#xff0c;倾向于在短周期内看到工作产品的新版本&#xff0c…...

JavaScript Math常用方法

math是JavaScript的一个内置对象&#xff0c;它提供了一些数学属性和方法&#xff0c;可以对数字进行计算&#xff08;用于Number类型&#xff09;。 math和其他全局对象不同&#xff0c;它不是一个构造器&#xff0c;math的所有方法和属性都是静态的&#xff0c;直接使用并传入…...

【C++】模板进阶

文章目录一、非类型模板参数1、非类型模板参数2、C11 中的 array 类二、模板的特化1、模板特化的概念2、函数模板特化3、类模板特化3.1 全特化3.2 偏特化三、模板的分离编译四、模板总结一、非类型模板参数 1、非类型模板参数 模板参数分为类型形参与非类型形参&#xff0c;类…...

三板斧解决leetcode的链表题

在《波奇学单链表》中我们提到单链表的两个特点单向性。头节点尾节点的特殊性导致分类讨论的情况。如何看单链表&#xff1f;让我们简化成下图cur表示当前节点&#xff0c;下图表示cur移动&#xff0c;圆圈表示值用哨兵卫节点(新的头节点)和把尾节点看成NULL来把头尾节点一般化…...

全生命周期的云原生安全框架

本博客地址&#xff1a;https://security.blog.csdn.net/article/details/129423036 一、全生命周期的云原生安全框架 如图所示&#xff1a; 二、框架说明 在上图中&#xff0c;我们从两个维度描述各个安全机制&#xff0c;横轴是开发和运营阶段&#xff0c;细分为编码、测试…...

【本地网站上线】ubuntu搭建web站点,并内网穿透发布公网访问

【本地网站上线】ubuntu搭建web站点&#xff0c;并内网穿透发布公网访问前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar3.2 创建隧道3.3 测试公网访问4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子…...

电脑怎么重装系统?教你轻松掌握这些方法

重新安装计算机系统有两种原因&#xff1a;一种是计算机系统可以正常使用&#xff0c;但是电脑比较卡&#xff0c;为了提高它的运行速度&#xff0c;所以想要通过重新安装系统来解决这个问题;另一种原因是计算机系统文件丢失&#xff0c;系统出现蓝屏&#xff0c;或者黑屏的情况…...

leetcode-每日一题-2379(简单,字符串)

久违的简单题......给你一个长度为 n 下标从 0 开始的字符串 blocks &#xff0c;blocks[i] 要么是 W 要么是 B &#xff0c;表示第 i 块的颜色。字符 W 和 B 分别表示白色和黑色。给你一个整数 k &#xff0c;表示想要 连续 黑色块的数目。每一次操作中&#xff0c;你可以选择…...

SLF4J日志框架在项目中使用

介绍 SLF4J全称“Simple Logging Facade for Java”&#xff0c;作为各种日志框架的简单门面。例如&#xff1a; java.util.logging、logback 、 reload4j等。只需要切换日志框架的jar包依赖就可以切换日志框架。 SLF4J支持的日志框架包含如下&#xff1a; log4j&#xff1a…...

Spark MLlib 模型训练

Spark MLlib 模型训练决策树随机森林GBDTSpark MLlib 开发框架下 : 监督学习 : 回归 (Regression) , 分类 (Classification) , 协同过滤 (Collaborative Filtering)非监督学习 : 聚类 (Clustering) 、频繁项集 (Frequency Patterns) 例子分类 : 算法分类 : 算法分类算法子分类…...

Python中变量的作用域精讲

文章目录前言一、局部变量二、全局变量前言 变量的作用域是指程序代码能够访问该变量的区域&#xff0c;如果超出该区域&#xff0c;再访问时就会出现错误。在程序中&#xff0c;一般会根据变量的 “有效范围” 将变量分为 “全局变量” 和 “局部变量”。 一、局部变量 局部变…...

数据仓库工程师的工作职责的相关介绍

1. BI 开发工程师的工作内容是什么&#xff1f; BI开发工程师&#xff08;Business Intelligence Developer&#xff09;是负责设计和开发企业级BI系统的专业人员。他们的主要工作是从多个数据源中提取、转换、加载和分析数据&#xff0c;以支持企业决策。以下是BI开发工程师的…...

ESP UART 介绍

1 UART 介绍 UART 是一种以字符为导向的通用数据链&#xff0c;可以实现设备间的通信。异步传输的意思是不需要在发送数据上添加时钟信息。这也要求发送端和接收端的速率、停止位、奇偶校验位等都要相同&#xff0c;通信才能成功。 1.1 UART 通信协议 一个典型的 UART 帧开始…...

第十三届蓝桥杯省赛Python大学B组复盘

目录 一、试题B&#xff1a;寻找整数 1、题目描述 2、我的想法 3、官方题解 4、另解 二、试题E&#xff1a;蜂巢 1、题目描述 2、我的想法 3、官方题解 三、试题F&#xff1a;消除游戏 1、题目描述 2、我的想法&#xff08;AC掉58.3%&#xff0c;剩下全超时&#x…...

linux入门---vim的配置

这里写目录标题预备知识如何配置vimvim一键配置预备知识 在配置vim之前大家首先得知道一件事就是vim的配置是一人一份的&#xff0c;每个用户配置的vim都是自己的vim&#xff0c;不会影响到其他人&#xff0c;比如说用户xbb配置的vim是不会影响到用户wj的&#xff0c;虽然不同…...

Python简写操作(for、if简写、匿名函数)

Python简写操作&#xff08;for、if简写、匿名函数&#xff09;1. for 简写1.1 一层 for 循环1.2 两层 for 循环2. if 简写3. for 与 if 的结合简写4. 匿名函数 lambda1. for 简写 举个例子&#xff1a; y [1, 2, 3, 4, 5, 6] result [(i * 2) for i in y] print(result)# …...

毕业设计常用模块之温湿度模块DHT11模块使用

DHT11是一款可以测量温度数据和湿度数据的传感器 产品特点 暖通空调、除湿器、农业、冷链仓储、测试及检测设备、消费品、汽车、自动控制、数据记录器、气 象站、家电、湿度调节器、医疗、其他相关湿度检测控制 外形尺寸 第3管脚&#xff1a;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...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...