当前位置:   article > 正文

Flutter控件--Row、Column和Stack_flutter column的高度

flutter column的高度

flutter控件练习demo地址github

一 Row 和 Column

1. 简介

因为 Row 和 Column 都是继承于 Flex,所以他们两个的属性也都是 Flex 的属性

  • Row 是 Flutter 中常用的控件。一个让 children 在水平方向依次排列 。如果 Row 空间 不足的话。 自身不带滚动的。
  • Column 也是 Flutter 中常用的控件。 一个 children 在垂直方向依次排列 。如果 Column 空间 不足的话。 自身不带滚动的。

2. 属性

2.1 mainAxisAlignment (主轴对准方式)

对于 Row 来说 , 水平是主轴。垂直是 交叉轴。 对于 Column 来说, 垂直是主轴。水平是 交叉轴 把 children 放到 主轴 的哪个位置 。 如果要验证这个属性,记住把 mainAxisSize 设置成 MainAxisSize.max ,

取值说明样式图片(Rowd 的demo)
MainAxisAlignment.start(默认值)把 children 放到主轴的头部
MainAxisAlignment.center把 children 放到主轴的中间
MainAxisAlignment.end把 children 放到主轴的尾部
MainAxisAlignment.spaceAround将主轴方向空白区域均分,使得children之间空间相等,但是首尾 childre 的空白部分为一半
MainAxisAlignment.spaceBetween将主轴方向空白区域均分,使得children之间空间相等,但是首尾childre靠近收尾,没有空细逢
MainAxisAlignment.spaceEvenly将主轴方向空白区域均分,使得children之间空间相等,包括首尾childre

2.2 mainAxisSize

也就是来规定自己( Row 或者 Column )的大小。

  • MainAxisSize.min : 主轴方向,包裹住 childre 即可。相当于 android 中的 wrap_content
  • MainAxisSize.max(默认值) : 主轴方向,铺满 ( Row 或者 Column )的父 Widget 的大小。 相当于 android 中的 match_parent

2.3 crossAxisAlignment (交叉轴)跟主轴垂直的一个轴

交叉轴 顾名思义: 就是 跟 主轴 垂直的 一个轴 对于 Row 。交叉轴 是 在垂直。对于 Column,交叉轴 是水平 。下面还是 以 Row 举个例子

取值说明图片demo(Row)
CrossAxisAlignment.start把 children 放到交叉轴的头部
CrossAxisAlignment.end把 children 放到交叉轴的尾部
CrossAxisAlignment.center把 children 放到交叉轴的中间
CrossAxisAlignment.stretch让children填满交叉轴方向无(没有测试出来,控件 找不到了)
CrossAxisAlignment.baseline让children 于 baseline 对齐,如果主轴是垂直的,那么这个值是当作开始 ,设置了此 属性 textBaseline 不能为 null

2.4 textDirection

children 在 主轴 怎样排列。 正方向排列还是反方向排列

Row

  • TextDirection.ltr : 表示在水平方向(主轴)。由左到右 , 左为头 , 右为尾
  • TextDirection.rtl :表示在水平方向(主轴)。由右到左 , 右为头 , 左为尾

Column

  • TextDirection.ltr : 表示在垂直方向(主轴)。由上到下 , 上为头 , 下为尾
  • TextDirection.rtl :表示在垂直方向(主轴)。由下到上 , 下为头 ,上为尾

2.5 verticalDirection

children 在 交叉轴 怎样排列。 正方向排列还是反方向排列

Row

  • VerticalDirection.down : 表示在垂直方向(交叉轴)。由上到下 , 上为头 , 下为尾
  • VerticalDirection.up :表示在垂直方向(交叉轴)。由下到上 , 下为头 , 上为尾

Column

  • VerticalDirection.down : 表示在水平方向(交叉轴)。由左到右 , 左为头 , 右为尾
  • TextDirection.rtl :表示在水平方向(交叉轴)。由右到左 , 右为头 , 左为尾

二 Stack

Flutter-Stack的使用说明

Stack的定义

Stack和Container,Column,Row基本上一样,都是一种存放其他Widget的容器,不同点在于Row、Column、Stash中存放的是一组Widget;Container每次只能放一个WIdget;具体请查看Stack的定义:
 

  1. Stack({
  2. Key key,
  3. this.alignment = AlignmentDirectional.topStart,//设置子Widget开始展示的位置,从顶部开始展示
  4. AlignmentDirectional.topCenter//从顶部中间开始展示
  5. AlignmentDirectional.topEnd//从顶部结束位置展示
  6. AlignmentDirectional.centerStart//从中间开始位置开始展示
  7. AlignmentDirectional.center//从正中间展示
  8. AlignmentDirectional.centerEnd//从中间结束位置展示
  9. AlignmentDirectional.bottomStart//从底部开始位置展示
  10. AlignmentDirectional.bottomCenter//从底部中间位置展示
  11. AlignmentDirectional.bottomEnd//从底部结束位置展示
  12. this.textDirection,//设置子widget的左右显示方位
  13. this.fit = StackFit.loose,//设置没有通过positioned包裹的子widget的size,loose表示,以他子widget最大的size展示
  14. StackFit.expand//stack的size等于他父widget的size
  15. this.overflow = Overflow.clip,子widget超出stack时的截取方式,参考Text的溢出截取方式
  16. List<Widget> children = const <Widget>[],//一组子widgets
  17. })

Stack的使用说明

Stack里面可以存放各种Widget,不过有一个缺点就是所有的子widget都是重叠放在一起的,请看事例代码

  1. Stack(
  2. // alignment: AlignmentDirectional.center,
  3. textDirection: TextDirection.rtl,
  4. // fit: StackFit.passthrough,
  5. children: <Widget>[
  6. Container(
  7. color: Colors.redAccent,
  8. width: 100.0,
  9. height: 100.0,
  10. child: Text('data'),
  11. ),
  12. Icon(Icons.settings),
  13. // Positioned(
  14. // top: 10,
  15. // left: 60,
  16. // child: Icon(Icons.settings),),
  17. Icon(Icons.opacity),
  18. Icon(Icons.ondemand_video),
  19. ],
  20. )

 为了能够使stack里面的子widget分开展示,需要借助于Positioned这个widget来辅助,可以通过Positioned来设置上下左右,宽高等属性,具体按照需要进行设置

  1. Stack(
  2. // alignment: AlignmentDirectional.center,
  3. textDirection: TextDirection.rtl,
  4. // fit: StackFit.passthrough,
  5. children: <Widget>[
  6. Container(
  7. color: Colors.redAccent,
  8. width: 100.0,
  9. height: 100.0,
  10. child: Text('data'),
  11. ),
  12. Positioned(
  13. top: 10,
  14. left: 60,
  15. child: Icon(Icons.settings),),
  16. Icon(Icons.opacity),
  17. Icon(Icons.ondemand_video),
  18. ],
  19. )

 

取代线性布局 (和Android中的LinearLayout相似,但是我感觉怎么这么像 FrameLayout 呢?),Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于Stack的上下左右四条边的位置。Stacks是基于Web开发中的绝度定位(absolute positioning )布局模型设计的。用于将多个childs相对于其框的边缘定位,多用于以简单方式重叠children

2.1 属性

  • alignment: 默认值。AlignmentDirectional.topStart ( AlignmentDirectional(-1.0, -1.0) )。 表示从左上角开始排 children
  • textDirection: 文本方向 , children 的流动方向
  • overflow: 表示 超过的部分是否裁剪掉 Overflow.visible 不剪掉。 Overflow.clip 减掉
  • fit: 让 children 怎样填充 Stack 。
    • StackFit.passthrough 不改变子节点约束 也就是说 children 是多大就是多大
    • StackFit.expand 子节点最大可能的占用空间 ,让 children 的大小 扩大到 Stack 的大小
    • StackFit.loose:放开了子节点宽高的约束,可以让子节点从0到最大尺寸

三 demo图片

demo 代码

  1. import 'package:flutter/material.dart';
  2. class LayoutDemo extends StatelessWidget {
  3. @override
  4. Widget build(BuildContext context) {
  5. // TODO: implement build
  6. return Scaffold(
  7. appBar: AppBar(
  8. title: Text("row"),
  9. centerTitle: true,
  10. ),
  11. body: RowDemo(),
  12. );
  13. }
  14. }
  15. class RowDemo extends StatelessWidget {
  16. @override
  17. Widget build(BuildContext context) {
  18. // TODO: implement build
  19. final _list = <Widget>[
  20. RaisedButton(
  21. disabledColor: Colors.red,
  22. child: Text("儿子1"),
  23. ),
  24. Text("儿子2"),
  25. Text("儿子3"),
  26. Text("儿子4"),
  27. Text("儿子5"),
  28. ];
  29. return Column(
  30. children: <Widget>[
  31. SizedBox(
  32. height: 30,
  33. ),
  34. Container(
  35. color: Colors.grey,
  36. child: Row(
  37. // 主轴(main axis)
  38. // 把 children 放到 Column 主轴 的哪个位置
  39. // end : 尾部, start :头部, center : 中间 ,spaceBetween:在 children 之间均匀地放置 空间 ,spaceAround : 每个 children
  40. mainAxisAlignment: MainAxisAlignment.start,
  41. // 此 Row 的宽度。默认是 MainAxisSize.max
  42. // MainAxisSize.min 是 包裹 children 的高度 即可 。android 中 相当于 wrap_content
  43. // MainAxisSize.max 是 铺满 Row 的父 Widget 的宽度 。android 中 相当于 match_parent
  44. // 如果设置成 MainAxisSize.min 。 那么 mainAxisAlignment 属性相当于无效。 因为是包裹 children
  45. mainAxisSize: MainAxisSize.max,
  46. // 交叉轴(cross axis)
  47. // 把 children 放到 Column 主轴 的哪个位置
  48. // end : 尾部, start :头部, center : 中间 ,
  49. crossAxisAlignment: CrossAxisAlignment.start,
  50. // children 在主轴 的排列顺序
  51. textDirection: TextDirection.ltr,
  52. // children 在 交叉轴 的排列顺序
  53. verticalDirection: VerticalDirection.down,
  54. children: _list,
  55. ),
  56. ),
  57. SizedBox(
  58. height: 30,
  59. ),
  60. SizedBox(
  61. width: 200,
  62. height: 200,
  63. child: Stack(
  64. alignment: AlignmentDirectional.topStart,
  65. // alignment: AlignmentDirectional(-1.0, -1.0),
  66. fit: StackFit.loose,
  67. overflow: Overflow.visible,
  68. children: <Widget>[
  69. Container(
  70. color: Colors.black,
  71. height: 200,
  72. width: 200,
  73. ),
  74. Container(
  75. color: Colors.deepPurple,
  76. height: 100,
  77. width: 100,
  78. ),
  79. Container(
  80. color: Colors.green,
  81. height: 50,
  82. width: 50,
  83. ),
  84. ],
  85. )),
  86. ],
  87. );
  88. }
  89. }


作者:android大哥
链接:https://juejin.cn/post/6844903849019310093
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1.Column 和Row 是横向关系的对比而已。

同样的,column 中的子widget 不能超过屏幕的剩余空间,不支持上下滚动。如果需要支持滚动则要使用ListView
如果只有一个child,可以考虑用Center或者Align来定位child。
demo

  1. body: new Column(
  2. children: <Widget>[
  3. new Text('eliver features faster'),
  4. new Text('Craft beautiful UIs'),
  5. new Expanded(
  6. child: new FittedBox(
  7. child: const FlutterLogo(),
  8. ))
  9. ],
  10. ),

效果如下: text,和 图片都是居中显示。

image.png


可以通过设置crossAxisAlignment属性改变对其方式,例如设置 crossAxisAlignmentrossAxisAlignment.start可以让child从左对齐,设置mainAxisSizeMainAxisSize.min可以是column最小化适应子控件。

demo如下

  1. body: new Column(
  2. crossAxisAlignment: CrossAxisAlignment.start,
  3. mainAxisSize: MainAxisSize.max,
  4. children: <Widget>[
  5. new Text('We move under cover and we move as one'),
  6. new Text('Through the night, we have ondd ddddddddddd ddddddd ddddddd ddddddddde shot to live another day'),
  7. new Text('We cannot let a stray gunshot give us away'),
  8. new Text('We will fight up close, seize the moment and stay in it'),
  9. new Text('It’s either that or meet the business end of a bayonet'),
  10. new Text('The code word is ‘Rochambeau,’ dig me?'),
  11. new Text('Rochambeau!',
  12. style: DefaultTextStyle
  13. .of(context)
  14. .style
  15. .apply(fontSizeFactor: 0.5)),
  16. ],
  17. ),

image.png

2.棘手的问题

  • 2.1当输入的垂直约束是无界限的怎么办?

当一个column嵌套在另一个column或者ListView中,并且这个column有一个或多个Expanded 或Flexible 的子控件时,会出现运行时异常,错误大概是:包含非零的flex 子控件,但是垂直约束是无界限。

刚才上面的异常主要是因为使用Flexible或Expanded意味这对于剩余空间是平均分配的,但是输入的垂直约束是无界限的,这样就意味有无限的剩余空间,显然无法平均分配。

解决这个问题的核心需要确认为什么,Column需要接受无界限的垂直约束。

  • 一个常见的原因是:column被嵌套在另一个column(内嵌的Column并没有使用Expanded或者Flexible)中。当column包裹他的非弹性子孩子(指的非ExpandedFlexible的子控件),column会传递子控件无界限约束因此子控件可以根据控制自己的大小(传递无限制约束通常意味着子控件需要自适应自己的内容)。在这种情况下,

解决方案通常是用Expanded来包裹里面的Column,并且指定它需要占外部的剩余空间,而不是让他占据所需要的任意空间。

  • 另一个原因是 在ListView或其他垂直带可滑动的控件中内嵌Column。这种场景下,确实存在无线的垂直空间(关键是整个垂直列表允许无限空间)。这时通常值得检查下内部的Colunm需要Expanded或者Flexible 子控件的原因:子类所需要实际的大小是多少?

典型的解决方案是移除内部的Expanded或者Flexible控件。

2.2.黄黑条纹警告线

当Column里面的内容超出了剩余空间,Column溢出了,并且里面的内容被裁剪了。在debug模式下,在溢出边沿出现黄黑条纹警告线意味这出了异常,并且会打印检测出现溢出的多少信息。
解决的方案通常是采用ListView代替Column,以便于在受限的垂直方向上面可以滚动。

3. Layout布局算法

这一部分主要描述Column在framework中的具体是如何渲染的。可以通过查看BoxConstraints了解具体的装载layout的数据模型。

Column进行布局主要包括6步:
step1> 为每个子节点设置一个空或零Flex因子(例如,那些没有展开的),其中包含无限制的垂直约束和输入的水平约束。如果crossAxisAlignment设置为CrossAxisAlignment.stretch而不是采用紧缩水平约束来匹配输入的最大宽度。
step2> 通过设置的flex因子,将剩余垂直空间分配给具有非零flex因子的孩子(例如 Expanded)例如,某个孩子拥有flex 因子2.0的将会是另一个flex因子为1.0的2倍垂直空间。
step3>使用与步骤1相同的水平约束来布局每个剩余的子节点,但是使用基于步骤2中分配的空间量的垂直约束来代替无限制的垂直约束。具有Flexible.fit属性为FlexFit.tight的子节点被给予严格的约束(即,强制填充分配的空间),具有Flexible.fit属性为FlexFit.look的子节点被给予松散约束(即,不强制填充分配的空间)。
step4>Column的宽度通常是子节点(通常满足输入的子节点的约束)的最大宽度。
step5> Column的高度取决于mainAxisSize属性。如果mainAxisSize设置为MainAxisSize.max,那么column的高度则是输入约束的最大高度。如果MainAxisSize设置为MainAxisSize.min,那么column的高度则是子节点(所输入的约束的目标结点)的高度之和。
step6>通过mainAxisAlignmentcrossAxisAlignment确定子节点的位置。例如,如果mainAxisAlignmentMainAxisAlignment.spaceBetween,则未分配给子节点的任何垂直空间被均匀地分割并放置在子节点之间。



作者:浩林Leon
链接:https://www.jianshu.com/p/47de9174cf0d
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/286577?site
推荐阅读
相关标签
  

闽ICP备14008679号