我正在快速开发应用程序,而我正在做的一部分工作是从服务器获取操作列表,然后为每个操作构建按钮。我试图将按钮显示为一个圆圈,并生成一个凸起的按钮小部件列表。然后,我尝试使用堆栈在一个圆圈中排列此列表,但是当我不知道要有多少个对象时(我知道它将在一个圆圈中),无法弄清楚如何使用定位在一个圆圈中定位对象范围约为3-15)。
这是我的堆栈的构建方法。假设所有方法,列表和变量均已正确定义并且可以正常工作。我只是担心对齐方式
@override
Widget build(BuildContext context) {
List<Widget> actions = [];
for(var action in widget.actionsList){
actions.add(RaisedButton(
onPressed: () => _handleAction(action[0]),
shape: CircleBorder(),
child: Text(action[1] + ': ' + action[2]),
));
}
return Scaffold(
body: Center(
child: Stack(
children: actions,
alignment: //HELP,
),
),
);
}
如果您对如何进行对齐有任何想法,或者有其他方法可以使按钮绕成一圈,请告诉我。我真的很想围成一个圈,但不愿嫁给不可能(我怀疑)或超级困惑。
谢谢!
答案 0 :(得分:1)
这就是我要怎么做。
TL; DR;
final actionsList = [
"one",
"two",
"three",
"four",
"five",
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Stack(
children: layedOutButtons(
centerOfCircle:
Offset(constraints.maxWidth, constraints.maxHeight) / 2,
circleRadius: 100,
),
),
),
);
}
Offset getCoordinateFromAngle({double radius, double angle}) => Offset(
radius * sin(angle),
radius * cos(angle),
);
List<Widget> layedOutButtons({
Offset centerOfCircle,
double circleRadius,
}) {
var buttonRadius = 25.0;
var dispatchAngle = pi * 2 / actionsList.length;
List<Widget> widgets = [];
var i = 0;
for (var action in actionsList) {
var position = getCoordinateFromAngle(
radius: circleRadius,
angle: dispatchAngle * i++,
);
widgets.add(
Positioned(
top: centerOfCircle.dy - position.dy - buttonRadius,
left: centerOfCircle.dx + position.dx - buttonRadius,
width: buttonRadius * 2,
height: buttonRadius * 2,
child: FloatingActionButton(
child: Text(action),
onPressed: () {},
),
),
);
}
return widgets;
}
说明
如果您想在一个圆上调度许多小部件,则必须:
centerOfCircle
,即该圆心的位置。为此,我使用LayoutBuilder
小部件来获取布局的约束并确定Stack
=>的中心(宽度/ 2,高度/ 2)。circleRadius
,即该圆的半径(在我的示例中为100)将这些数据提供给layedOutButtons
,该数据将与Positioned
小部件一起分发到小部件上。
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Stack(
children: layedOutButtons(
centerOfCircle: Offset(constraints.maxWidth, constraints.maxHeight) / 2,
circleRadius: 100,
),
),
),
);
}
List<Widget> layedOutButtons({
Offset centerOfCircle,
double circleRadius,
}) {
List<Widget> widgets = [];
for (var action in actionsList) {
widgets.add(
Positioned(
child: FloatingActionButton(
child: Text(action),
onPressed: () {},
),
),
);
}
return widgets;
}
现在,您需要根据其数量定义如何在圆上分配窗口小部件。例如,有2个小部件,它们以180°的角度相互分派(意味着一个在圆的顶部,在底部一个。如果有4个,则以90°的角度相互分派,依此类推。请注意,用弧度(非度)。
var dispatchAngle = pi * 2 / actionsList.length;
然后,您必须基于角度定义圆上点的坐标(x,y)(请参见this)。
Offset getCoordinateFromAngle({double radius, double angle}) => Offset(
radius * sin(angle),
radius * cos(angle),
);
使用它来填充top
小部件的left
和Positioned
属性。
List<Widget> layedOutButtons({
Offset centerOfCircle,
double circleRadius,
}) {
var dispatchAngle = pi * 2 / actionsList.length;
List<Widget> widgets = [];
var i = 0;
for (var action in actionsList) {
var position = getCoordinateFromAngle(
radius: circleRadius,
angle: dispatchAngle * i++, //increment angle for each widget
);
widgets.add(
Positioned(
top: centerOfCircle.dy - position.dy, //something's wrong here
left: centerOfCircle.dx + position.dx, //something's wrong here
child: FloatingActionButton(
child: Text(action),
onPressed: () {},
),
),
);
}
return widgets;
}
现在,除了未对齐之外,一切都准备就绪。这是由于这些小部件是根据其左上角定位的。我们要优化位置,使其与小部件的中心匹配。
var buttonRadius = 25.0;
Positioned(
top: centerOfCircle.dy - position.dy - buttonRadius,
left: centerOfCircle.dx + position.dx - buttonRadius,
width: buttonRadius * 2,
height: buttonRadius * 2,
child: FloatingActionButton(
child: Text(action),
onPressed: () {},
),
),