【问题标题】:Relative positioning of stack child using child center in Flutter在 Flutter 中使用子中心对堆栈子进行相对定位
【发布时间】:2025-12-11 04:15:02
【问题描述】:

我的布局的一部分显示了顶部带有对象的图像。图像和对象位于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'),
        ],
      ),
    );
  }
}

【问题讨论】:

  • 请详细说明您希望小部件的布局方式。添加您想要的图像也会有所帮助。
  • 试过CustomMultiChildLayout?
  • @pskink 谢谢你的作品!我会写一个答案。
  • @anmol.majhail 我试图澄清这个问题
  • 好,我很高兴听到它有效 ;-)

标签: flutter dart


【解决方案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),因此红色圆圈以右下角为中心:

【讨论】: