在Flutter中使用子中心相对放置堆子

时间:2019-06-18 08:10:20

标签: flutter dart

我的版式的一部分显示的图像顶部是对象。图像和对象位于Stack中。对于对象位置,我知道对象中心相对于图像的相对坐标。例如,(0,0)表示对象中心应位于图像的左上角,而(0.23,0.7)表示“中心位于宽度的23%和高度的70%”。我知道对象的大小,但是我不知道先验将为图像分配多少大小。

为此,我尝试使用Align,但是它不使用对象的中心:例如,将AlignAlignment(1,1)放在对象的右下角角。然后,我尝试添加一个转换以将对象的中心转换为(0,0),但这仅适用于右下角,例如,当将中心与Alignment(0,0)对齐时,位置将是错误的。

我曾考虑使用Positioned小部件,但是我不知道build函数中的图像大小。

如何正确定位对象?在下面的示例中,如何使红色圆圈居中于绿色矩形的右下角? (也适用于其他坐标)

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: <Widget>[
          Expanded(
            child: Column(
              children: <Widget>[
                Expanded(
                  child: Container(
                    color: Colors.blue,
                    child: Stack(
                      alignment: Alignment.center,
                      children: [
                        AspectRatio(
                          aspectRatio: 1.5,
                          child: Container(
                            color: Colors.green,
                          ),
                        ),
                        Align(
                          alignment: Alignment(1,
                              1), // Should put circle center on bottom-right corner
                          child: Container(
                            width: 100,
                            height: 100,
                            // transform: Matrix4.translationValues(50, 50, 0), // doesn't work except for bottom-right corner
                            decoration: BoxDecoration(
                              color: Colors.red,
                              shape: BoxShape.circle,
                            ),
                          ),
                        )
                      ],
                    ),
                  ),
                ),
                Text('Bottom widget'),
              ],
            ),
          ),
          Text('Right widget'),
        ],
      ),
    );
  }
}

1 个答案:

答案 0 :(得分:1)

这是pskink建议的基于CustomMultichildLayout的解决方案:

enum _Slot {
  image,
  circle,
}

class MyDelegate extends MultiChildLayoutDelegate {
  final FractionalOffset objectCenter;

  MyDelegate({@required this.objectCenter});

  @override
  void performLayout(Size size) {
    Size imageSize = Size.zero;
    Offset imagePos = Offset.zero;

    if (hasChild(_Slot.image)) {
      imageSize = layoutChild(_Slot.image, BoxConstraints.loose(size));

      // Center the image in the available space
      imagePos = (size - imageSize as Offset) * 0.5;
      positionChild(_Slot.image, imagePos);
    }

    if (hasChild(_Slot.circle)) {
      Size childSize = layoutChild(_Slot.circle, BoxConstraints());
      positionChild(
          _Slot.circle,
          imagePos +
              objectCenter.alongSize(imageSize) -
              childSize.center(Offset.zero));
    }
  }

  @override
  bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => false;
}

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: <Widget>[
          Expanded(
            child: Column(
              children: <Widget>[
                Expanded(
                  child: Container(
                    color: Colors.blue,
                    child: Center(
                      child: CustomMultiChildLayout(
                        delegate:
                            MyDelegate(objectCenter: FractionalOffset(1, 1)),
                        children: [
                          LayoutId(
                            id: _Slot.image,
                            // Use AspectRatio to emulate an image
                            child: AspectRatio(
                              aspectRatio: 1.5,
                              child: Container(
                                color: Colors.green,
                              ),
                            ),
                          ),
                          LayoutId(
                            id: _Slot.circle,
                            child: Container(
                              width: 100,
                              height: 100,
                              decoration: BoxDecoration(
                                color: Colors.red,
                                shape: BoxShape.circle,
                              ),
                            ),
                          )
                        ],
                      ),
                    ),
                  ),
                ),
                Text('Bottom widget'),
              ],
            ),
          ),
          Text('Right widget'),
        ],
      ),
    );
  }
}

传递给委托的偏移量可以是任何相对坐标。在上面的示例中,我通过了(1,1),因此红色圆圈位于右下角的中心:

enter image description here