水平堆叠内的中心项目

时间:2019-12-29 06:30:26

标签: swift swiftui centering vstack hstack

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

HStack{

      Text("test")

      Spacer()

      item2()

      Spacer()

      Text("test")
}

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

如何使item2()始终居中?

谢谢

4 个答案:

答案 0 :(得分:1)

我将提出以下起点(最简单的情况...请在下面阅读原因)

Center horizontally one element

如所见,它确实提供了带有正确对齐的侧边元素的居中偏移/无帧偏移,但是...存在缺点-它仅适用于最简单的变体 如果事先知道在用户运行时这三个文本元素永远不应该重叠。如果是这种情况(确实有这种情况),那么这种方法就可以了。但是,如果左/右文本可能会在运行时增长,则将需要更多计算以根据中心元素的宽度来限制.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)
}

更新:这是一种可以限制一侧不重叠居中的方法(包含异步更新,因此应在 Live Preview 或模拟器中进行测试)< / p>

所以...如果左侧文本是动态的,并且要求剪切尾随符号,那么这就是可能的方式...

enter image description here

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

enter image description here

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))
        }
    }
}

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

答案 1 :(得分:1)

我遇到了同样的问题,@ Asperi的解决方案也起作用了,但是如果我在列表中使用多行文本,则会遇到一些性能问题,并且会遇到一些性能问题。

以下解决方案解决了所有问题。

HStack(alignment: .center) {
  Text("test")
      .frame(maxWidth: .infinity)
  item2()
  Text("test")            
      .frame(maxWidth: .infinity)
}

答案 2 :(得分:0)

您可能需要添加一些自定义的Alignment组件。

                       extension HorizontalAlignment{
                    private enum MyHAlignment: AlignmentID {
                        static func defaultValue(in d: ViewDimensions) -> CGFloat {
                            return d[HorizontalAlignment.center]
                        }
                    }
                     static let myhAlignment = HorizontalAlignment(MyHAlignment.self)
                }







         HStack{
                Spacer()
                  Text("jjjjjjjjjj")
                 Spacer()
                  Image("image").alignmentGuide(.myhAlignment) { (ViewDimensions) -> CGFloat in
                      return ViewDimensions[HorizontalAlignment.center]
                  }
                Spacer()

                  Text("test")

              }.frame(alignment: Alignment(horizontal: .myhAlignment, vertical: .center))

答案 3 :(得分:0)

要使视图居中,可以使用ZStack:

ZStack {
    item2()

    HStack {
        Text("test")
        Spacer()
        Text("test")
    }
}