Flutter-布局

作者: 雨亦有种执着 | 来源:发表于2021-12-06 14:39 被阅读0次

一、介绍

flutter布局需要先了解flutter所有布局的widget,首先flutter布局分为Container、RenderObjectWidget和ParentDataWidget。而RenderObject中经常使用的有SingleChildRenderObjectWidget(单节点)和MultiChildRenderObjectWidget(多节点)。

布局.png
  1. Container
  2. SingleChildRenderObjectWidget(单节点)
    • Opacity
    • ClipOval
    • ClipRRect
    • PhysicalModel
    • Align
      • Center
    • Padding
    • SizeBox
    • FractionallySizedBox
  3. MultiChildRenderObjectWidget(多节点)
    • Stack
    • Wrap
    • Flex
      • Column
      • Row
    • Flow
  4. ParentDataWidget
    • Positioned
    • Flexible
      • Expanded

二、Container

2.1、 container在flutter中非常常见,它是结合了绘制(painting)、定位(position)以及尺寸(size)的组合widget

2.2、 属性

属性 含义
key container唯一标识,用于查找更新
alignment 对齐方式
padding container内部间距
color 背景颜色
decoration 绘制在child后面的装饰,设置了decoration的话,就不能设置color,否则会报错。需要在decoration中设置color
foregroundDecoration 绘制在child前面的装饰
width 宽度,设置为double.infinity可以强制在宽度上撑满,不设置,则根据child和父节点两者一起布局
height 高度,设置为double.infinity可以强制在高度上撑满
constraints 添加到child上额外的约束条件
margin 围绕在decoration和child之外的空白区域,不属于内容区域
transform 设置container的变换矩阵,类型为Matrix4
child container中的内容widget

2.3、图层解析: color层 -> gradient层 -> image层

container.png

2.4、container使用场景

  • 设置间隔(单纯的间隔可以使用Padding)
  • 设置背景颜色
  • 设置圆角或者边框(使用ClipRRect也是可以的)
  • 设置对齐(也可以使用Align)
  • 设置背景图片(也可以用stack)

2.5、container示例代码

Container(
        width: 100,
        height: 100,
        alignment: Alignment.center,
        margin: EdgeInsets.fromLTRB(100, 20, 0, 0),
        child: Text('container'),
        constraints: BoxConstraints(maxHeight: double.infinity),
        decoration: BoxDecoration(
          color: Colors.red,
          border: Border.all(color: Colors.amber, width: 3),
          borderRadius: BorderRadius.all(Radius.circular(10)),
          gradient: LinearGradient(
            colors: [Colors.red, Colors.cyan],
          ),
          image: DecorationImage(
            image: NetworkImage(
                'https://img1.baidu.com/it/u=2756706381,1092999478&fm=26&fmt=auto&gp=0.jpg'),
          ),
        ),
        transform: Matrix4.rotationZ(0.0),
      );

三、SingleChildRenderObjectWidget(单节点)

3.1、Padding

flutter中基础的widget,可以为子节点设置内间距。当padding没有child的时候,它会产生一个宽为left+right,高为top+bottom的区域,当padding的child不为空的时候会将约束传递给child。一般在使用间距的地方使用。

Padding(
        padding: EdgeInsets.fromLTRB(50, 100, 50, 100),
        child: Container(
          color: Colors.amber,
        ),
      );

3.2、Align

设置child的对齐方式,并根据child的尺寸调整自身的尺寸。

Align(
        alignment: Alignment.center,
        child: Text('Align'),
      );

3.3、 Opacity

设置透明度

Opacity(
        opacity: 0.3,
        child: Image(
            image: NetworkImage(
                'https://img1.baidu.com/it/u=2756706381,1092999478&fm=26&fmt=auto&gp=0.jpg')),
      );

3.4、 ClipRRect

用于矩形圆角裁剪组件

ClipRRect(
        borderRadius: BorderRadius.circular(10),
        child: Image.network(
          'https://img1.baidu.com/it/u=2756706381,1092999478&fm=26&fmt=auto&gp=0.jpg',
          width: 100,
          height: 100,
          fit: BoxFit.fill,
        ),
      );

3.5、 PhysicalModel

用于圆形裁剪,但是可以添加阴影和Z轴

PhysicalModel(
        color: Colors.amber,
        borderRadius: BorderRadius.circular(10),
        shadowColor: Colors.blueAccent,
        elevation: 10,
        clipBehavior: Clip.antiAlias,
        child: Image.network(
          'https://img1.baidu.com/it/u=2756706381,1092999478&fm=26&fmt=auto&gp=0.jpg',
          width: 100,
          height: 100,
          fit: BoxFit.fill,
        ),
      );

3.6、 SizedBox

给组件绘制区域大小

SizedBox(
          width: 100,
          height: 100,
          child: Image(
            image: NetworkImage(
                'https://img1.baidu.com/it/u=2756706381,1092999478&fm=26&fmt=auto&gp=0.jpg'),
            fit: BoxFit.fill,
          ),
        )

3.7、 FractionallySizedBox

百分比布局,可以通过widthFactor或者heightFactor设置宽高占比

Container(
        margin: EdgeInsets.fromLTRB(30, 30, 0, 0),
        color: Colors.amber,
        height: 200,
        width: 200,
        child: FractionallySizedBox(
          alignment: Alignment.center,
          widthFactor: 0.5,
          heightFactor: 0.5,
          child: Container(
            color: Colors.red,
          ),
        ),
      )

四、MultiChildRenderObjectWidget(多节点)

4.1、 Stack

子组件叠加布局,也称绝对布局

stack.png
Stack(
        fit: StackFit.loose,
        children: <Widget>[
          Container(
            margin: EdgeInsets.fromLTRB(10, 20, 0, 0),
            color: Colors.amber,
            width: 300,
            height: 300,
          ),
          Positioned(
            top: 20,
            left: 20,
            child: Container(
              color: Colors.blueAccent,
              width: 100,
              height: 100,
            ),
          ),
        ],
      )

4.2、 column垂直布局

4.2.1- 属性
属性 类型 默认值 含义
mainAxisAlignment MainAxisAlignment start 主轴方向对齐方式
crossAxisAlignment CrossAxisAlignment center 交叉轴方向对齐方式
mainAxisSize MainAxisSize max 主轴尺寸
textDirection TextDirection null 文本方向
verticalDirection VerticalDirection down 竖直方向
textBaseline TextBaseline null 基准线
children List<Widget> <Widget>[] 子节点
4.2.2- 代码示例
Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.stretch,
       mainAxisSize: MainAxisSize.max,
        verticalDirection: VerticalDirection.down,
        children: <Widget>[
          Container(
            color: Colors.red,
            height: 50,
            width: 50,
          ),
          Container(
            color: Colors.amber,
            height: 50,
            width: 100,
            child: Text('stretch'),
            alignment: Alignment.center,
          ),
          Container(
            color: Colors.blueAccent,
            height: 50,
            width: 150,
          )
        ],
      )
column.png
4.2.3- mainAxisAlignment属性解释

mainAxisAlignment: start:顶头 center:居中 end:接尾 spaceAround:中间的孩子均分,两头的孩子空一半 spaceBetween:顶头接尾其他均分 spaceEvenly:均匀分布

mainAxisAlignment.png
4.2.4- crossAxisAlignment属性解释

crossAxisAlignment: start:顶头 center:居中 end:接尾 stretch:伸展

crossAxisAlignment.png
4.2.5- mainAxisSize属性解释

mainAxisSize: max:父容器没有约束的话,column自身会尽可能延伸 min:不会延伸,只会包裹自己

mainAxisSize.png

4.3、 row水平布局

属性和column属性一致,只是方向不同,一个竖直方向一个水平方向。使用方法也类似。

Row(
        children: <Widget>[
          Container(
            color: Colors.amber,
            height: 100,
            width: 50,
          ),
          Expanded(
            child: Container(
              color: Colors.cyanAccent,
              height: 100,
              width: 50,
            ),
          ),
        ],
      )

4.4、 wrap流式布局

Wrap可以实现流布局,单行的Wrap跟Row一样,单列的Wrap则跟Colum一样.但是Row和Column都是单行单列的,Wrap可以多行多列。

4.4.1、示例代码
Wrap(
            direction: Axis.horizontal,
            alignment: WrapAlignment.start,
            runAlignment: WrapAlignment.start,
            spacing: 10, //主轴方向上的间距
            runSpacing: 10, //run的间距
            crossAxisAlignment: WrapCrossAlignment.end,
            children: [
              Container(
                color: Colors.amber,
                height: 50,
                width: 50,
              ),
              Container(
                color: Colors.amber,
                height: 50,
                width: 50,
              ),
              Container(
                color: Colors.amber,
                height: 50,
                width: 50,
              ),
              Container(
                color: Colors.amber,
                height: 50,
                width: 50,
              ),
              Container(
                color: Colors.amber,
                height: 50,
                width: 50,
              ),
              Container(
                color: Colors.amber,
                height: 50,
                width: 50,
              ),
              Container(
                color: Colors.amber,
                height: 50,
                width: 50,
              ),
            ],
          )
wrap.png

4.5、 flow流式布局

Wrap能做的事情,flow也能做。但是flow会比较复杂点。flow类似于OC中CollectionLayout,需要自己实现子组件的位置以及大小。但是flow的性能比较好,灵活。

4.5.1、示例代码
Flow(
            delegate: CustomFlowDelegate(margin: EdgeInsets.all(5)),
            children: <Widget>[
              Container(
                width: 80.0,
                height: 80.0,
                color: Colors.red,
              ),
              Container(
                width: 80.0,
                height: 80.0,
                color: Colors.green,
              ),
              Container(
                width: 80.0,
                height: 80.0,
                color: Colors.blue,
              ),
              Container(
                width: 80.0,
                height: 80.0,
                color: Colors.yellow,
              ),
              Container(
                width: 80.0,
                height: 80.0,
                color: Colors.brown,
              ),
              Container(
                width: 80.0,
                height: 80.0,
                color: Colors.purple,
              ),
            ],
          ),

自定义FlowDelegate

class CustomFlowDelegate extends FlowDelegate {
  EdgeInsets margin = EdgeInsets.zero;
  CustomFlowDelegate({required this.margin});

  @override
  void paintChildren(FlowPaintingContext context) {
    var x = margin.left;
    var y = margin.top;
    //计算每一个子widget的位置
    for (int i = 0; i < context.childCount; i++) {
      var w = context.getChildSize(i)!.width + x + margin.right;
      if (w < context.size.width) {
        context.paintChild(i,
            transform: new Matrix4.translationValues(x, y, 0.0));
        x = w + margin.left;
      } else {
        x = margin.left;
        y += context.getChildSize(i)!.height + margin.top + margin.bottom;
        //绘制子widget(有优化)
        context.paintChild(i,
            transform: new Matrix4.translationValues(x, y, 0.0));
        x += context.getChildSize(i)!.width + margin.left + margin.right;
      }
    }
  }

  @override
  Size getSize(BoxConstraints constraints) {
    return Size(double.infinity, 200);
  }

  @override
  bool shouldRepaint(covariant FlowDelegate oldDelegate) {
    throw UnimplementedError();
  }
}

运行结果:

flow.png

五、ParentDataWidget

5.1、Positioned

绝对定位布局,用于指定组件的具体位置

Positioned(
            top: 20,
            left: 20,
            child: Container(
              color: Colors.blueAccent,
              width: 100,
              height: 100,
            ),
          )
Positioned.png

5.2、Expanded

Expanded组件可以使row、column或者flex子组件在其主轴上展开并填充可用空间。如果多个组件展开的话,会按照比例分割。
Tip:Expanded组件要在row、column或者flex的子组件中使用。具有两个属性,child:子组件,flex:所占比例

Row(
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                alignment: Alignment.center,
                color: Colors.red,
                child: Text('flex=1'),
                height: 50,
              ),
            ),
            Expanded(
              flex: 2,
              child: Container(
                alignment: Alignment.center,
                color: Colors.yellow,
                child: Text('flex=2'),
                height: 50,
              ),
            ),
          ],
        )
Expanded.png

六、不常用的布局

布局 说明
FittedBox 主要做两件事情,一缩放二位置,FittedBox会根据自己的尺寸来缩放并调整子组件的位置,使其能适合其尺寸
AspectRatio 调整child到指定的宽高比
ConstrainedBox 给child额外添加限制
LimitedBox 限制控制的宽高
Offstage/Visibility 通过一个参数控制组件的显示
Transform 平移、缩放、旋转等操作
CustomSingleChildLayout 需要自己实现delegate,来确定child位置,和flow类似
IndexedStack 继承stack,控制第几个子组件显示
Table 表格布局

相关文章

网友评论

    本文标题:Flutter-布局

    本文链接:https://www.haomeiwen.com/subject/hsapxrtx.html