可容纳多个组件, 需要自己制定排布的代理,可以高强度自定义组件的排布,实现普通布局无法达到的效果。布局王者,当之无愧。
相关组件
Flow圆形排布
<br />【children】 : 组件列表 【List<Widget>】<br />【delegate】 : 代理 【FlowDelegate】<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/326147/1589509260717-1a0a2af9-bc1a-4b9a-8d66-faa45b258e01.png#align=left&display=inline&height=321&margin=%5Bobject%20Object%5D&name=image.png&originHeight=321&originWidth=341&size=51121&status=done&style=none&width=341)
import 'dart:math';
import 'package:flutter/material.dart';
class CircleFlow extends StatelessWidget {
final data = List.generate(
16,
(index) => index.isEven
? "assets/images/icon_head.png"
: "assets/images/wy_300x200.jpg");
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 300,
alignment: Alignment.center,
child: Flow(
delegate: _CircleFlowDelegate(),
children: data
.map((e) => CircleAvatar(backgroundImage: AssetImage(e)))
.toList(),
),
);
}
}
class _CircleFlowDelegate extends FlowDelegate {
@override //绘制孩子的方法
void paintChildren(FlowPaintingContext context) {
double radius = context.size.shortestSide / 2;
print(context.getChildSize(0));
var count = context.childCount;
var perRad = 2 * pi / count;
for (int i = 0; i < count; i++) {
var cSizeX = context.getChildSize(i).width / 2;
var cSizeY = context.getChildSize(i).height / 2;
var offsetX = (radius - cSizeX) * cos(i * perRad) + radius;
var offsetY = (radius - cSizeY) * sin(i * perRad) + radius;
context.paintChild(i,
transform: Matrix4.translationValues(
offsetX - cSizeX, offsetY - cSizeY, 0.0));
}
}
@override
bool shouldRepaint(FlowDelegate oldDelegate) {
return true;
}
}
Flow圆形与动画结合
<br />通过动画来更改周围组件的位置实现效果<br />![197.gif](https://cdn.nlark.com/yuque/0/2020/gif/326147/1589509301897-1dd5c874-18d2-4433-8239-24591c9a88c3.gif#align=left&display=inline&height=332&margin=%5Bobject%20Object%5D&name=197.gif&originHeight=332&originWidth=370&size=863901&status=done&style=none&width=370)
import 'dart:math';
import 'package:flutter/material.dart';
class BurstFlow extends StatefulWidget {
static final data = List.generate(
16,
(index) => index.isEven
? "assets/images/icon_head.png"
: "assets/images/wy_300x200.jpg");
static final show = Container(
width: 300,
height: 300,
alignment: Alignment.center,
child: BurstFlow(
children: data
.map((e) => CircleAvatar(backgroundImage: AssetImage(e)))
.toList(),
menu: CircleAvatar(
backgroundImage: AssetImage('assets/images/icon_head.png'),
)));
final List<Widget> children;
final Widget menu;
BurstFlow({@required this.children, @required this.menu});
@override
_BurstFlowState createState() => _BurstFlowState();
}
class _BurstFlowState extends State<BurstFlow>
with SingleTickerProviderStateMixin {
AnimationController _controller;
double _rad = 0.0;
bool _closed = true;
@override
void initState() {
_controller = AnimationController(
duration: Duration(milliseconds: 1000), vsync: this)
..addListener(() => setState(
() => _rad = (_closed ? (_controller.value) : 1 - _controller.value)))
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
_closed = !_closed;
}
});
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Flow(
delegate: _BurstFlowDelegate(_rad),
children: [
...widget.children,
InkWell(
onTap: () {
_controller.reset();
_controller.forward();
},
child: widget.menu)
],
);
}
}
class _BurstFlowDelegate extends FlowDelegate {
final double rad;
_BurstFlowDelegate(this.rad);
@override //绘制孩子的方法
void paintChildren(FlowPaintingContext context) {
double radius = context.size.shortestSide / 2;
var count = context.childCount - 1;
var perRad = 2 * pi / count;
for (int i = 0; i < count; i++) {
print(i);
var cSizeX = context.getChildSize(i).width / 2;
var cSizeY = context.getChildSize(i).height / 2;
var offsetX = rad * (radius - cSizeX) * cos(i * perRad) + radius;
var offsetY = rad * (radius - cSizeY) * sin(i * perRad) + radius;
context.paintChild(i,
transform: Matrix4.translationValues(
offsetX - cSizeX, offsetY - cSizeY, 0.0));
}
context.paintChild(context.childCount - 1,
transform: Matrix4.translationValues(
radius - context.getChildSize(context.childCount - 1).width / 2,
radius - context.getChildSize(context.childCount - 1).height / 2,
0.0));
}
@override
bool shouldRepaint(FlowDelegate oldDelegate) {
return true;
}
}