堆栈对齐方式,用于不确定数量的子代

时间:2019-07-25 03:48:16

标签: flutter dart flutter-layout

我正在快速开发应用程序,而我正在做的一部分工作是从服务器获取操作列表,然后为每个操作构建按钮。我试图将按钮显示为一个圆圈,并生成一个凸起的按钮小部件列表。然后,我尝试使用堆栈在一个圆圈中排列此列表,但是当我不知道要有多少个对象时(我知道它将在一个圆圈中),无法弄清楚如何使用定位在一个圆圈中定位对象范围约为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,
        ),
      ),
    );
  }

如果您对如何进行对齐有任何想法,或者有其他方法可以使按钮绕成一圈,请告诉我。我真的很想围成一个圈,但不愿嫁给不可能(我怀疑)或超级困惑。

谢谢!

1 个答案:

答案 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;
  }

说明

如果您想在一个圆上调度许多小部件,则必须:

  1. 定义centerOfCircle,即该圆心的位置。为此,我使用LayoutBuilder小部件来获取布局的约束并确定Stack =>的中心(宽度/ 2,高度/ 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小部件的leftPositioned属性。

  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: () {},
  ),
),