Flow
1. 简介
Flow 是一个实现流式布局算法的控件。流式布局在大前端是很常见的布局方式,但是一般使用 Flow 很少,因为其过于复杂,很多场景下都会去使用 Wrap 。
2. 属性
delegate:影响 Flow 具体布局的 FlowDelegate。
其中 FlowDelegate 包含如下几个方法:
- getConstraintsForChild: 设置每个 child 的布局约束条件,会覆盖已有的;
- getSize:设置 Flow 的尺寸;
- paintChildren:child 的绘制控制代码,可以调整尺寸位置,写起来比较的繁琐;
- shouldRepaint:是否需要重绘;
- shouldRelayout:是否需要重新布局。
其中,我们平时使用的时候,一般会使用到 paintChildren 以及 shouldRepaint 两个方法。
3. 使用场景
Flow 在一些定制化的流式布局中,有可用场景,但是一般写起来比较复杂,但胜在灵活性以及其高效。
4. 实例
1. 效果图
2. 示例代码
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('流式布局'),
),
body: Center(
child: Flow(
delegate: TestFlowDelegate(margin: EdgeInsets.all(10.0)),
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,),
],
),
)
)
);
}
}
class TestFlowDelegate extends FlowDelegate {
EdgeInsets margin;
TestFlowDelegate({
this.margin = EdgeInsets.zero});
double width = 0;
double height = 0;
@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: 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: Matrix4.translationValues(x, y, 0.0));
x += context.getChildSize(i)!.width + margin.left + margin.right;
}
}
}
@override
Size getSize(BoxConstraints constraints) {
// 指定Flow的大小,简单起见我们让宽度竟可能大,但高度指定为200,
// 实际开发中我们需要根据子元素所占用的具体宽高来设置Flow大小
return Size(double.infinity, 200.0);
}
@override
bool shouldRepaint(FlowDelegate oldDelegate) {
return oldDelegate != this;
}
}
Wrap
1. 简介
流式布局组件,如果内容宽度超出屏幕宽度,会自动折行显示。
2. 属性
-
direction:主轴(mainAxis)的方向,默认为水平。
-
alignment:主轴方向上的对齐方式,默认为start。
-
spacing:主轴方向上的间距。
-
runAlignment:run的对齐方式。run可以理解为新的行或者列,如果是水平方向布局的话,run可以理解为新的一行。
-
runSpacing:run的间距。
-
crossAxisAlignment:交叉轴(crossAxis)方向上的对齐方式。
-
textDirection:文本方向。
-
verticalDirection:定义了children摆放顺序,默认是down,见Flex相关属性介绍。
3. 使用场景
对于一些需要按宽度或者高度,让child自动换行布局的场景,可以使用,但是Wrap可以满足的场景,Flow一定可以实现,只不过会复杂很多,但是相对的会灵活以及高效很多。
4. 实例
1. 效果图
2. 代码
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('流式布局'),
),
body: Center(
child: Wrap(
spacing: 8.0,
runSpacing: 4.0,
children: <Widget>[
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.green.shade300, child: new Text('AH', style: TextStyle(fontSize: 10.0),)),
label: Text('Kevin'),
),
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.green.shade300, child: new Text('ML', style: TextStyle(fontSize: 10.0),)),
label: Text('Lafayette'),
),
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.green.shade300, child: new Text('HM', style: TextStyle(fontSize: 10.0),)),
label: Text('Aaron'),
),
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.green.shade300, child: new Text('JL', style: TextStyle(fontSize: 10.0),)),
label: Text('Laurens'),
),
],
),
)
)
);
}
}