Я создаю приложение во флаттере, и часть того, что я делаю, — это получение списка действий с сервера, а затем создание кнопок для каждого действия. Я пытаюсь отобразить кнопки по кругу и создать список приподнятых виджетов кнопок. Затем я пытаюсь использовать стек, чтобы расположить этот список по кругу, но не могу понять, как использовать позиционирование для размещения объектов по кругу, когда я не знаю, сколько объектов у меня будет (я знаю, что они будут в диапазон примерно 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,
),
),
);
}
Если у вас есть какие-либо идеи о том, как сделать выравнивание или другой способ сделать это, чтобы сделать круг из кнопок, пожалуйста, дайте мне знать. Я действительно хочу сделать круг, но не зациклен на том, чтобы это было невозможно (в чем я сомневаюсь) или сверхсложно.
Спасибо!





Вот как бы я это сделал.
TL;ДР;
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) точки на окружности на основе угла (см. это).
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: () {},
),
),
Попробуйте взять виджеты в виде списка и показать ограниченное количество виджетов в стеке с помощью виджета «Позиционирование».