Flutter - 基础布局

return Align(
widthFactor: 5, // 宽度是child宽度的5倍
heightFactor: 5, // 高度是child高度的5倍
alignment: Alignment.center,
child: Icon(Icons.pets),
);
}
}

一般情况下, 会直接在外层嵌套 Container 直接指定确切的宽度值, 而不会使用 widthFactor

2、Padding

一般的 Widget 是没有 padding 属性的(Container 除外), 如果希望对子 widget 有 padding 效果的话, 可以为子 widget 套一层 Padding, Padding 只有 2 个属性, 分别是 child 和 padding, padding 属性对应 EdgeInsetsGeometry 类型的对象, 一般会结合 EdgeInsets 的几个常量命名构造函数来使用:

  • padding: 内间距
  • EdgeInsets.all(8.0): 统一指定内间距
  • EdgeInsets.symmetric(horizontal: 8, vertical: 8): 纵向、横向分开指定内间距
  • EdgeInsets.fromLTRB(8, 8, 8, 8): 上下左右分开指定内间距
  • EdgeInsets.only(left: 8): 只指定一个方向内间距

class PaddingDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: item(“hello lqr”),
),
Divider(height: 1, color: Colors.black),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: item(“hello gitlqr”),
),
Divider(height: 1, color: Colors.black),
Padding(
padding: EdgeInsets.fromLTRB(8, 8, 8, 8),
child: item(“hello charylin”),
),
Divider(height: 1, color: Colors.black),
Padding(
padding: EdgeInsets.only(left: 8),
child: item(“hello charylin”),
),
Divider(height: 1, color: Colors.black),
],
);
}

Widget item(String content) {
return Text(
content,
style: TextStyle(
fontSize: 30,
backgroundColor: Colors.red,
color: Colors.white,
),
);
}
}

3、Container

Container 是 Flutter 中最特殊的 widget, 可以指定尺寸、内外间距、2D 转换等:

  • width: 宽度
  • height: 高度
  • alignment: 子 widget 对齐方式
  • padding: 内间距, EdgeInsetsGeometry 类型, 一般使用子类 EdgeInsets
  • margin: 外间距, EdgeInsetsGeometry 类型, 一般使用子类 EdgeInsets
  • transform: 2D 转换, Matrix4 类型
  • color: 背景色(注意:与 decoration 中的 color 冲突,只能选择一个设置)
  • decoration:BoxDecoration()
  • color: 背景色
  • border: 边框样式, BoxBorder 类型, 常用 Border.all(width: 5) 来指定
  • borderRadius: 边框圆角, BorderRadiusGeometry 类型, 常用 BorderRadius.circular(8) 来指定
  • boxShadow:BoxShadow()
  • color: 阴影颜色
  • offset: 阴影偏移量
  • spreadRadius: 延伸,在 offset 的基础上对 x,y 分别增加

class ContainerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
// width、height不指定,默认是包裹内容
width: 200,
height: 200,
child: Icon(Icons.pets, size: 50, color: Colors.white),
// 子元素所在位置
alignment: Alignment.topLeft,
padding: EdgeInsets.all(20),
margin: EdgeInsets.all(10),
// 旋转5度,缩小一半
transform: Matrix4.rotationZ(degree2Radia(5)).scaled(0.5),
color: Colors.red,
),
Container(
width: 200,
height: 200,
child: Icon(Icons.accessibility, size: 50, color: Colors.white),
// color与decoration冲突,两者只有选择其中一个
// color: Colors.red,
decoration: BoxDecoration(
color: Colors.red, // 背景色
border: Border.all(width: 5, color: Colors.blueAccent), // 边框
borderRadius: BorderRadius.circular(8), // 圆角
boxShadow: [
BoxShadow(
color: Colors.blueGrey, // 阴影颜色
offset: Offset(10, 10), // 阴影偏移量
spreadRadius: 5, // 延伸,相当于offset为 15,15
),
]),
)
],
);
}

double degree2Radia(double degree) {
return degree * pi / 180;
}
}

二、多子布局 Widget

多子布局, 顾名思义就是只能包含多个子控件的 widget

1、Flex

Flutter 中的 Flex 与 css 中的 flex 布局很类似, 可以很灵活的控制内部子 widget 的摆放, 不过一般情况下不会直接使用, 而是使用其子类 Row / Column:

  • Row/Column 继承自 Flex
  • Row = Flex(direction: Axis.horizontal)
  • mainAxis(主轴): 水平向右
  • crossAxis(交叉轴): 竖直向下
  • Column = Flex(direction: Axis.vertical)
  • mainAxis(主轴): 竖直向下
  • crossAxis(交叉轴): 水平向右

默认情况下, Row 在水平方向上会尽可能占据比较大的空间, 这是因为其 mainAxisSize 属性默认为 MainAxisSize.max 导致:

Column 与 Row 除了方向不同, 其它基本一致, 故掌握 Row 的情况后, Column 自然也会掌握

class ButtonRowDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
/// Row特点:
/// - 水平方向尽可能占据比较大的空间
/// * 如果水平方向希望包裹内容,可以设置 mainAxisSize = min
/// - 垂直方向包裹内容
return Column(
children: [
RaisedButton(
child: Row(
children: [Icon(Icons.bug_report), Text(“bug报告(MainAxisSize.max)”)],
),
onPressed: () {},
),
RaisedButton(
child: Row(
mainAxisSize: MainAxisSize.min, // 包裹内容。包裹是max占满父widget
children: [Icon(Icons.bug_report), Text(“bug报告(MainAxisSize.min)”)],
),
onPressed: () {},
),
],
);
}
}

2、Row

Row 比较重点的是主轴及交叉轴的对齐:

  • MainAxisAlignment:
  • start: 主轴的开始位置挨个摆放元素
  • end: 主轴的结束位置挨个摆放元素
  • center: 主轴的中心点对齐
  • spaceBetween: 左右两边的间距为 0,其它元素之间平分间距
  • spaceAround: 左右两边的间距是其它元素之间的间距的一半
  • spaceEvenly: 所有的间距平分空间
  • CrossAxisAlignment:
  • start: 交叉轴的起始位置对齐
  • end: 交叉轴的结束位置对齐
  • center: 中心点对齐(默认值)
  • baseline: 基线对齐(必须有文本的时候才起效果)
  • 使用 baseline 对齐必须指定 textBaseline, 否则会报错.
  • stretch: 先让 Row 占据交叉轴尽可能大的空间, 将所有子 widget 交叉轴的高度, 拉伸到最大

class RowDemo1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
itemRow(“start”, MainAxisAlignment.start, “center”, CrossAxisAlignment.center),
itemRow(“end”, MainAxisAlignment.end, “center”, CrossAxisAlignment.center),
itemRow(“center”, MainAxisAlignment.center, “center”, CrossAxisAlignment.center),
itemRow(“spaceBetween”, MainAxisAlignment.spaceBetween, “center”, CrossAxisAlignment.center),
itemRow(“spaceAround”, MainAxisAlignment.spaceAround, “center”, CrossAxisAlignment.center),
itemRow(“spaceEvenly”, MainAxisAlignment.spaceEvenly, “center”, CrossAxisAlignment.center),
],
);
}

Widget itemRow(
String mainAxisAlignmentStr,
MainAxisAlignment mainAxisAlignment,
String crossAxisAlignmentStr,
CrossAxisAlignment crossAxisAlignment) {
return Container(
height: 120,
margin: const EdgeInsets.only(bottom: 8.0),
color: Colors.pink[100],
child: Stack(
fit: StackFit.expand,
children: [
Row(
mainAxisAlignment: mainAxisAlignment,
crossAxisAlignment: crossAxisAlignment,
// textDirection: TextDirection.ltr, // rtl: 从右到左排版; ltr: 从左到右排版(默认)
children: [
Container(width: 80, height: 60, color: Colors.red),
Container(width: 120, height: 100, color: Colors.green),
Container(width: 90, height: 80, color: Colors.blue),
Container(width: 50, height: 120, color: Colors.orange),
],
),
Positioned(
left: 0,
bottom: 0,
child: Text(
“GitLqr >>> main: m a i n A x i s A l i g n m e n t S t r , c r o s s : mainAxisAlignmentStr , cross: mainAxisAlignmentStr,cross:crossAxisAlignmentStr”,
style: TextStyle(fontSize: 20, backgroundColor: Colors.black54, color: Colors.white),
),
)
],
),
);
}
}

class RowDemo2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 基线对齐
return Column(
children: [
itemRow(“spaceEvenly”, MainAxisAlignment.spaceEvenly, “start”, CrossAxisAlignment.start),
itemRow(“spaceEvenly”, MainAxisAlignment.spaceEvenly, “center”, CrossAxisAlignment.center),
itemRow(“spaceEvenly”, MainAxisAlignment.spaceEvenly, “end”, CrossAxisAlignment.end),
itemRow(“spaceEvenly”, MainAxisAlignment.spaceEvenly, “stretch”, CrossAxisAlignment.stretch),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.baseline,
// alphabetic 与 ideographic 这2种基线几乎没差
textBaseline: TextBaseline.ideographic,
children: [
Container(width: 80,height: 60, color: Colors.red, child: Text(“Hellxo”, style: TextStyle(fontSize: 20))),
Container(width: 120, height: 100, color: Colors.green, child: Text(“Woxrld”, style: TextStyle(fontSize: 30)),),
Container(width: 90, height: 80, color: Colors.blue, child: Text(“abxc”, style: TextStyle(fontSize: 12))),
Container(width: 50, height: 120, color: Colors.orange, child: Text(“cxba”, style: TextStyle(fontSize: 40))),
],
),
],
);
}

Widget itemRow(
String mainAxisAlignmentStr,
MainAxisAlignment mainAxisAlignment,
String crossAxisAlignmentStr,
CrossAxisAlignment crossAxisAlignment) {
return Container(
height: 140,
margin: const EdgeInsets.only(bottom: 8.0),
color: Colors.pink[100],
child: Stack(
fit: StackFit.expand,
children: [
Row(
mainAxisAlignment: mainAxisAlignment,
crossAxisAlignment: crossAxisAlignment,
// textDirection: TextDirection.ltr, // rtl: 从右到左排版; ltr: 从左到右排版(默认)
children: [
Container(width: 80, height: 60, color: Colors.red),
Container(width: 120, height: 100, color: Colors.green),
Container(width: 90, height: 80, color: Colors.blue),
Container(width: 50, height: 120, color: Colors.orange),
],
),
Positioned(
left: 0,
bottom: 0,
child: Text(
“GitLqr >>> main: m a i n A x i s A l i g n m e n t S t r , c r o s s : mainAxisAlignmentStr , cross: mainAxisAlignmentStr,cross:crossAxisAlignmentStr”,
style: TextStyle(fontSize: 20, backgroundColor: Colors.black54, color: Colors.white),
),
)
],
),
);
}
}

最后一组是 CrossAxisAlignment.baseline 的效果, 可以看到不管文字多大, 字母 x 的底部都是在一条线上的, 这就是基线对齐.
值得注意的是, 使用 CrossAxisAlignment.baseline 必须同时指定基线 textBaseline(默认值为null), 其值 TextBaseline.ideographicTextBaseline.alphabetic 几乎没差

3、Column

Column 与 Row 都是继承自 Flex, 两者除了在方向上有区别外, 其他特性几乎完全一样, 这里只补充一点它们排版方向上的不同之处:

  • Row: 排版方向 TextDirection
  • rtl: 从右到左排版
  • ltr: 从左到右排版(默认)
  • Column: 排版方向 VerticalDirection
  • up: 从下到上排版
  • down: 从上到下排版(默认)

class ColumnDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
verticalDirection: VerticalDirection.down,
// up: 从下到上排版; down: 从上到下排版(默认)
children: [
Container(width: 80, height: 60, color: Colors.red),
Container(width: 120, height: 100, color: Colors.green),
Container(width: 90, height: 80, color: Colors.blue),
Container(width: 50, height: 120, color: Colors.orange),
Text(
“GitLqr >>> VerticalDirection.down”,
style: TextStyle(fontSize: 20, backgroundColor: Colors.black54, color: Colors.white),
),
],
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
verticalDirection: VerticalDirection.up,
// up: 从下到上排版; down: 从上到下排版(默认)
children: [
Container(width: 80, height: 60, color: Colors.red),
Container(width: 120, height: 100, color: Colors.green),
Container(width: 90, height: 80, color: Colors.blue),
Container(width: 50, height: 120, color: Colors.orange),
Text(
“GitLqr >>> VerticalDirection.up”,
style: TextStyle(fontSize: 20, backgroundColor: Colors.black54, color: Colors.white),
),
],
),
),
]);
}
}

4、Flexible(Expanded)

  • Flexible 中的属性:

  • fit: 填充模式

  • tight: 子控件强制填满可用空间

  • loose: 子控件只占用本身大小

  • flex: 当 fit 为 tight 时才会生效 (重点: width 比 = flex 比)

  • 不指定 flex 时: 按等分的方式来拉伸 Flexible 直至填满可用空间, 相当于 flex 都是 1

  • 有指定 flex 时: 按 flex 的比例来拉伸 Flexible 直至填满可用空间, 此时原本的 width 已经无效了

  • Expanded = Flexible(fit: FlexFit.tight)

  • 当 Flex(Row/Column)还有可用空间时, 拉伸子控件大小

  • 当子控件超出 Flex(Row/Column)空间时, 缩小子控件大小

class ExpandedDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
item1(),
tip(“Flexible fit: FlexFit.tight flex: 1”),
item2(),
tip(“Expanded flex: 1 , flex: 1 (width: 120)”),
item3(),
tip(“Expanded flex: 1 , flex: 2 (width: 10000)”),
],
);
}

Widget item1() {
return Row(
children: [
Flexible(
fit: FlexFit.tight,
flex: 1,
child: Container(width: 80, height: 60, color: Colors.red),
),
Flexible(
fit: FlexFit.tight,

最后

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。

还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

Android 基础知识点

Java 基础知识点

Android 源码相关分析

常见的一些原理性问题

希望大家在今年一切顺利,进到自己想进的公司,共勉!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。

还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

Android 基础知识点

Java 基础知识点

Android 源码相关分析

常见的一些原理性问题

[外链图片转存中…(img-lSkIlGM4-1714698694768)]

希望大家在今年一切顺利,进到自己想进的公司,共勉!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值