一、介绍
flutter布局需要先了解flutter所有布局的widget,首先flutter布局分为Container、RenderObjectWidget和ParentDataWidget。而RenderObject中经常使用的有SingleChildRenderObjectWidget(单节点)和MultiChildRenderObjectWidget(多节点)。
- Container
- SingleChildRenderObjectWidget(单节点)
- Opacity
- ClipOval
- ClipRRect
- PhysicalModel
- Align
- Center
- Padding
- SizeBox
- FractionallySizedBox
- MultiChildRenderObjectWidget(多节点)
- Stack
- Wrap
- Flex
- Column
- Row
- Flow
- 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.png2.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(
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:均匀分布
4.2.4- crossAxisAlignment属性解释
crossAxisAlignment: start:顶头 center:居中 end:接尾 stretch:伸展
4.2.5- mainAxisSize属性解释
mainAxisSize: max:父容器没有约束的话,column自身会尽可能延伸 min:不会延伸,只会包裹自己
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();
}
}
运行结果:
五、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 | 表格布局 |
网友评论