大家好,我是 17。
本文在 3.31 日全站综合热榜第一。
新手礼包一共 3 篇文章,每篇都是描述尽量详细,实例讲解,包会!
- Flutter Row 实例 —— 新手礼包
- Flutter TextField UI 实例 —— 新手礼包
- Flutter TextField 交互实例 —— 新手礼包
本篇介绍 Row 的用法,用实例讲解 flex 弹性布局原理。本来在 Flutter 弹性布局的基石: Flex 和 Flexible 一文中的内容已经包含 Row 了,但因为 Row 太常用了,所以单写一篇。
Row 的尺寸
默认情况下, Row 在宽度上尽量大,在高度上只要能包住所有的 children 即可。
第一个示例给出全部代码,后面的只给出 Row 的代码。在 Row 的外面加一个 Container ,是为了给 Row 加一个 border,方便查看。减去 margin,padding,border 后 ,Row 的宽度为 300。
MaterialApp(
home:Scaffold(
body:Container(
width:342,
alignment:Alignment.center,
child:Container(
padding:constEdgeInsets.all(10),
margin:constEdgeInsets.all(10),
decoration:BoxDecoration(border:Border.all(color:Colors.blue)),
child:Row(
children:[Container(
width:100,
height:50,
color:constColor.fromARGB(255,82,143,222),),],)))));
在本例中,Row 的宽度达到允许的最大值 300。高度为 50,正好可以包含蓝色块的高度。
MainAxisSize.min
可以让 Row 的宽度也正好能包含 children。
Row(
mainAxisSize:MainAxisSize.min,
children:[Container(
width:100,
height:50,
color:constColor.fromARGB(255,82,143,222),),],);
mainAxisSize:MainAxisSize.min
让 Row 的宽度收缩,直到正好包含 所有 children 为止。本例中,正好包含蓝色块,最终宽度为 100。
mainAxisSize 的默认值是
mainAxisSize.max
非弹性布局
非弹性布局是说在 children 中没有 Expanded,Flexible 这种有 flex 参数的 child。
Row(
children:[Container(
width:100,
height:50,
color:constColor.fromARGB(255,82,143,222),),constText("IAM17",
style:TextStyle(color:Color(0xFFC45F84), fontSize:24),)],);
非弹性布局中,Row 的 children 在宽度方面没有限制, child 按自己期望的尺寸在水平方向依次排列。如果 children 的总宽度没有超过 Row 的宽度,没有什么问题。如果超过了 Row 的宽度,在开发环境下,会给出警告。
比如修改 Container 的 width:100 为
width:400
,这个时候 Row 已经没有多余的空间给 Text 了,甚是连 Container 也放不下。
在生产环境中,多出来的部分会被直接截断。
弹性布局
弹性布局是说在 children 中有 Expanded,Flexible 这种有 flex 参数的 child。
简单来说,Row 分配空间的过程是这样的。
- 先分配非弹性 child,比如 Container,Text,这些没有 flex 属性的 Widget。
- 把剩余的空间按 flex 值的大小,分给所有的弹性块。
- 如果是用 Expanded 包起来的 child, child 的大小就是 第 2 步分配空间的大小;如果是用 Flexible 包起来,child 的大小可以从 0 到 第 2 步分配空间的大小 之间自行决定。
这里说的 Flexible 的 fit 参数的值为
FlexFit.loose
。Expanded 就是 fit 参数为
FlexFit.tight
的 Flexible。
让 child 占用所有分配到的空间,用 Expanded 包起来
Row(
children:[Expanded(
child:Container(
width:100,
height:50,
color:constColor.fromARGB(255,82,143,222),)),constText("IAM17",
style:TextStyle(color:Color(0xFFC45F84), fontSize:24),)],)
Row 的宽度为 300,先给非弹性块 Text 分配固定大小空间,剩余的全分给的 Expanded。child 蓝色块占用所有 Expanded 分配到的空间。
我们注意到 Container 的 width 是 100,实际上,就算是这里写 0,或写 1000 都没有关系,用 Expanded 包起来的 child 的 width 属性会被忽略。
Expanded 包起来的 child 的 width 是不能自定义的,如果 child 要自定义 width 又要保持弹性布局怎么办?用 Flexible!
让 child 可以在分配到的空间内自行决定大小,用 Flexible 包起来。
在下面的例子中 Row 总的可用宽度为 300,两个 Container 各占 100,还余 100 空白在两个 Container 之间
Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children:[Container(
width:100,
height:50,
color:Colors.blue,),Container(
width:100,
height:50,
color:Colors.red,),],)
现在我们把第一个 container 用 Flexible 包起来。
Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children:[Flexible(
child:Container(
width:100,
height:50,
color:Colors.blue,)),Container(
width:100,
height:50,
color:Colors.red,),],)
重新执行查看效果,发现没什么变化。这是因为 总宽度为 300,分给非弹性红色块 100后还有 200, 唯一的弹性块拿到 200。蓝色块的 100 在分配到的空间范围内,所以没有什么反应。
把第一个 Container 的 width 加大到 150 查看效果,发现第一个 Container 的宽度变为 150 了。同理 150 也在 分配到的 200 之内。
继续加大 width 的宽度到 200,发现他们已经紧贴到一起了。继续加大就没有任何效果了,但也不会报错。
继续加大到 200 以上就超过分配到的 200了,所以宽度不再增加。不会报错是因为蓝色块被 Flexible 限制在 200 以内,加上红色块的总宽度在 300 以内,没有超出,当然不会报错。
如果左面 Container 的 宽度不是我们指定的,而是 Container 的 child 撑起来的,那么就可以实现宽度自适应的布局效果,不用担心会超出边界。
Flexible 的 flex 与 fit 参数
Flexible 的 flex 决定了可以分配多少剩余空间。fit 参数决定 child 能否自行决定大小。
看下面的的例子,红色块为固定宽度,绿蓝为弹性宽度。在
fit: FlexFit.tight
的情况下,绿色块和红色块的 width 无效。因为 Flexible 的 flex 已经决定了宽度值,child 只能用这个值不能修改。
Row(children:[Container(
width:20, height:50, color:Colors.red),Flexible(
fit:FlexFit.tight,
flex:1,
child:Container(
width:100, height:50, color:Colors.green)),Flexible(
fit:FlexFit.tight,
flex:2,
child:Container(
width:100, height:50, color:Colors.blue))]
本例中 Row 的宽度为 320,首先分配 20 给固定宽度的红色块,剩余的 300 由两个弹性块瓜分。根据 flex 值,绿色块得到 100,蓝色块得到 200。Flex 值越大,得到的空间越大。
fit: FlexFit.tight
的 Flexible ,一般是用 Expanded。
在
fit: FlexFit.loose
的情况下,绿色块和红色块的 width 是有作用的,可以在 0 和最大值之间自定义自己的宽度。
我们把第二个 Flexible 的 fit: FlexFit.tight 修改为
fit: FlexFit.loose
,蓝色块的 width 起作用了,显示为 100 宽。
我们调整一下摆放方式,蓝色块省出来的 100 空间被填充到各个块之间了。
child:Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,...
在 children 之间加空白。
在 children 之间增加固定空白用 SizedBox
我们发现 Container 和 文本紧挨在一起了,想要他们之间有一个距离。可以用 Padding 把 Container 或 Text 包起来,但是这样写起来比较麻烦,而且多了一个层级,也不美观,不如用 SizedBox。
Row(
children:[Container(
width:100,
height:50,
color:constColor.fromARGB(255,82,143,222),),constSizedBox(width:20,),constText("IAM17",
style:TextStyle(color:Color(0xFFC45F84), fontSize:24),)],)
在 children 之间增加弹性空白用 Spacer
Row(
children:[Container(
width:100,
height:50,
color:constColor.fromARGB(255,82,143,222),),constSpacer(),constText("IAM17",
style:TextStyle(color:Color(0xFFC45F84), fontSize:24),)],)
文本 “IAM17” 与 蓝色块 之间的空白是 文本 “IAM17” 与 文本 “Flutter” 之间空白宽度的两倍。Row 的宽度如果增加或缩小,空白的宽度也会增加会缩小,但会保持两倍的关系。
平均分配空白
平均分配空白用 mainAxisAlignment 参数,具体用法详见 Flutter Wrap 图例。虽然讲的是 Wrap Widget,但是 alignment 与 Row 的 mainAxisAlignment 用法是一样的。比如两端对齐:
Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,...
Row 嵌套
Row 嵌套的时候需要注意下,因为一不小心会报错。
Row(
children:[Row(children:[Expanded(
child:Container(
width:100,
height:50,
color:Color.fromARGB(255,210,74,137),))]),],)
Expanded 是要占据所有的可用空间,内层的 Row 在宽度可以是无限,Expanded 无法占据无限空间,所以报错。解决的办法很简单,让 内层的 Row 的宽度有限就可以了。
Row(
children:[Expanded(
child:Row(children:[Expanded(
child:Container(
width:100,
height:50,
color:Color.fromARGB(255,210,74,137),))])),],)
或者给 Row 加一个宽度约束。比如用 SizedBox 包起来。
Row(
children:[SizedBox(
width:150,
child:Row(children:[Expanded(
child:Container(
width:100,
height:50,
color:Color.fromARGB(255,210,74,137),))])),],);
用 Flexible 包起来也是可以的,Flexible 与 Expanded 的区别在于 Flexible 给 child loose 约束,Expanded 给 child tight 约束。通俗一点的说法是 Flexible 的 child 的宽度可以从 0 到 最大值之间自己决定。Expanded 的 child 的宽度只能是固定值,不能修改。
Row 嵌套的时候报错本质上是因为宽度无限,遇到其它宽度无限的场景也会出现这样的问题,比如 ListView 横向滚动的时候,把 Row 嵌套在 ListView 中也会有类似的问题。
ListView(
scrollDirection:Axis.horizontal,
children:[Row(children:[Expanded(
child:Container(
width:100,
height:50,
color:Color.fromARGB(255,210,74,137),))]),],)
解决办法相同,也是把 Row 用 Flexible 或 Expanded 包起来,或加一个宽度约束。
ListView(
scrollDirection:Axis.horizontal,
children:[Expanded(
child:Row(children:[Expanded(
child:Container(
width:100,
height:50,
color:Color.fromARGB(255,210,74,137),))])),],);
到这里 Flutter Row 的常用的用法就都介绍完了。谢谢观看!
版权归原作者 IAM17前端 所有, 如有侵权,请联系我们删除。