1

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

HStack{

      Text("test")

      Spacer()

      item2()

      Spacer()

      Text("test")
}

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

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

谢谢

4

4 回答 4

5

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

水平居中一个元素

正如它所看到的,它确实提供了居中的无帧移位和正确对齐的侧面元素,但是......有一个缺点-只有在事先知道这三个文本元素不应该在用户中重叠的情况下,它才会在这种最简单的变体中工作运行。如果是这样(真的有这种情况),那么这种方法就可以了。但是,如果左/右文本可能在运行时增长,则需要更多的计算来通过.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)
}

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

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

在此处输入图像描述

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

在此处输入图像描述

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)需要额外的布局,并且解决方案增长,但想法是一样的。希望这对某人有帮助。

于 2019-12-29T09:23:51.333 回答
2

我遇到了同样的问题,@Asperi 的解决方案有效,但是如果我在列表中使用它,我会遇到多行文本问题和一些性能问题。

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

HStack(alignment: .center) {
  Text("test")
      .frame(maxWidth: .infinity)
  item2()
  Text("test")            
      .frame(maxWidth: .infinity)
}
于 2020-06-05T07:51:22.620 回答
0

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

                       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))
于 2019-12-29T07:29:08.623 回答
0

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

ZStack {
    item2()

    HStack {
        Text("test")
        Spacer()
        Text("test")
    }
}
于 2019-12-29T09:23:59.110 回答