文章目录
  1. 1. Wrap
  2. 2. Flow

流式布局,子 Widget 超出屏幕会自动折行

Wrap

Wrap 和 Row 一样包含 direction、crossAxisAlignment、textDirection、verticalDirection 属性,作用相同,多出下面几个属性

  • spacing 主轴方向 ziWidget 间距
  • runSpacing 纵轴方向间距
  • runAlignment 纵轴方向对齐方式

Flow

Flow 比较复杂,通常用在自定义布局或者性能要求较高的场景,Flow 拥有以下优点

  • 性能好 Flow 是一个队 child 尺寸以及位置调整非常高效的控件。用转换矩阵在对 child 进行位置的调整进行优化,Flow 定位过后,如果 child 尺寸或者位置发生了变化,在 FlowDlegate 中的 painChildren()方法调用context.paintChild进行重绘,并没有实际调整 Widget 位置
  • 灵活 需要实现 FlowDelegate 的paintChildren()方法,需要计算 children 的位置,自定义布局策略

缺点

  • 复杂
  • 不能自适应子 Widget 大小,必须通过制定父容器的大小或者实现 FlowDelegate 的getSize返回固定大小

简单实现流式布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class FlowPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flow'),
),
body: Flow(
delegate: MyFlowDelegate(),
children: <Widget>[
Ball(80, Colors.cyan),
Ball(70, Colors.purple),
Ball(90, Colors.grey),
Ball(50, Colors.red),
Ball(10, Colors.green),
Ball(20, Colors.black),
Ball(40, Colors.blue),
Ball(50, Colors.pink),
Ball(100, Colors.orange),
],
),
);
}
}

class MyFlowDelegate extends FlowDelegate {
@override
void paintChildren(FlowPaintingContext context) {
var x = 0.0;
var y = 0.0;
var maxHeight = 0.0;
for (int i = 0; i < context.childCount; i++) {
var w = context.getChildSize(i).width + x;
var h = context.getChildSize(i).height;
if (w < context.size.width) {
// 小于宽之间排在同一行
context.paintChild(i,
transform: new Matrix4.translationValues(x, y, 0.0));
x = w;
maxHeight = max(maxHeight, h);
} else {
x = 0.0;
y += maxHeight;
//绘制子widget(有优化)
context.paintChild(i,
transform: new Matrix4.translationValues(x, y, 0.0));
x += context.getChildSize(i).width;
}
}
}

@override
Size getSize(BoxConstraints constraints) {
return super.getSize(constraints);
}

@override
bool shouldRepaint(FlowDelegate oldDelegate) {
return oldDelegate != this;
}
}

class Ball extends StatelessWidget {
double _size;
Color _color;

Ball(double size, Color color) {
this._size = size;
this._color = color;
}

@override
Widget build(BuildContext context) {
return Container(
width: _size,
height: _size,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_size / 2), color: _color),
);
}
}
文章目录
  1. 1. Wrap
  2. 2. Flow