水平堆栈内的中心项目

Eva*_*van 3 centering swift swiftui vstack hstack

如果水平堆栈中有 3 个项目,我想我可以这样做:

HStack{

      Text("test")

      Spacer()

      item2()

      Spacer()

      Text("test")
}
Run Code Online (Sandbox Code Playgroud)

将 item2() 置于两个文本视图之间的中心。然而,这样做的问题是 item2() 不一定总是居中,因为,可以说 Text("test") 更改为 Text("a") 或其他内容。这会导致问题,并且第二个项目并不总是位于屏幕中央。

我怎样才能使 item2() 始终居中?

谢谢

Asp*_*eri 7

我建议以下起点(最简单的情况......请阅读下面的原因)

水平居中一个元素

正如所见,它确实提供了居中的无框架移位和正确对齐的侧面元素,但是......有一个缺点-只有事先知道这三个文本元素在用户中永远不应该重叠,它才会在这种最简单的变体中工作运行。如果是这样的话(确实有这样的情况),那么这种方法就可以了。但是,如果左/右文本可能在运行时增长,则需要更多的计算来根据.frame(maxWidth:)居中元素的宽度来限制它们的宽度......该变体更复杂,但它是可行的。

var body: some View {
        ZStack {
            HStack {
                Text("Longer side")
                Spacer()
                Text("One")
            }
            item2()
        }
    }

private func item2() -> some View {
    Text("CENTER")
        .background(Color.yellow)
        .border(Color.red)
}
Run Code Online (Sandbox Code Playgroud)

更新:这是限制一侧不重叠居中的可能方法(包含异步更新,因此应在实时预览或模拟器中进行测试)

所以...如果左侧文本是动态的并且需要剪切尾随符号,那么它可能会这样...

在此输入图像描述

并且它会自动适应设备方向的变化

在此输入图像描述

struct TestHorizontalPinCenter: View {

    @State var centerFrame: CGRect = .zero
    
    private let kSpacing: CGFloat = 4.0
    var body: some View {
            ZStack {
                HStack {
                    Text("Longer side very long text to fit")
                        .lineLimit(1)
                        .frame(maxWidth: (centerFrame == .zero ? .infinity : centerFrame.minX - kSpacing), alignment: .leading)

                    Spacer()
                    
                    Text("One")
                }
                item2()
                    .background(rectReader($centerFrame))
            }
        }
    
    private func item2() -> some View {
        Text("CENTER")
            .background(Color.yellow)
            .border(Color.red)
    }

    func rectReader(_ binding: Binding<CGRect>) -> some View {
        return GeometryReader { (geometry) -> AnyView in
            let rect = geometry.frame(in: .global)
            DispatchQueue.main.async {
                binding.wrappedValue = rect
            }
            return AnyView(Rectangle().fill(Color.clear))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果需要包裹左侧,则.lineLimit(nil)需要额外的布局,以及解决方案的增长,但想法是相同的。希望这对某人有帮助。