GeometryReader 和 .frame 的对齐

Alignment for GeometryReader and .frame

我正在使用 GeometryReader() 和 .frame() 来展示它们的可比性并玩弄它们的宽度。 但是,当宽度小于最小值时,包裹在 GeometryReader() 中的对象没有居中对齐。 演示请参考附件gif。

你能帮我对齐一下吗?

理想:

当前:

struct ExampleView: View {
@State private var width: CGFloat = 50

var body: some View {
    VStack {
        SubView()
            .frame(width: self.width, height: 120)
            .border(Color.blue, width: 2)
        
        Text("Offered Width is \(Int(width))")
        Slider(value: $width, in: 0...200, step: 5)
      }
   }
}

struct SubView: View {
    var body: some View {
        GeometryReader { geometry in
            Rectangle()
                .fill(Color.yellow.opacity(0.6))
                .frame(width: max(geometry.size.width, 120), height: max(geometry.size.height, 120))
        }
    }
}

那是因为 GeometryReader 没有将其子项居中。

您必须通过添加 .position 修饰符或 .offset.

手动定位 Rectangle

.position 将相对于父级中心移动矩形框的原点。

.offset 不会更改框架,而是会更改渲染(像 CGAffineTransform 一样进行翻译)。

您的 Rectangle 的以下修饰符将在视觉上产生相同的结果(尽管在幕后有所不同):

Rectangle()
    .fill(Color.yellow.opacity(0.6))
    .frame(width: max(geometry.size.width, 120), height: max(geometry.size.height, 120))
    .position(x: geometry.size.width / 2, y: geometry.size.height / 2)

let rectWidth = max(geometry.size.width, 120)
Rectangle()
    .fill(Color.yellow.opacity(0.6))
    .frame(width: rectWidth, height: max(geometry.size.height, 120))
    .offset(x: ((geometry.size.width - rectWidth) / 2), y: 0)

请注意,您的矩形框超出了其父项的边界。我建议避免这种情况,因为它会导致在屏幕上布置其他 UI 元素时出现各种困难。

您可以反过来构建它(除非您的实际目标只是了解 GeometryReader 的工作原理):

struct ExampleView: View {
    @State private var width: CGFloat = 50

    var body: some View {
        VStack {
            let minWidth: CGFloat = 120
            let subViewWidth: CGFloat = max(minWidth, width)
            SubView(desiredWidth: width)
                .frame(width: subViewWidth, height: 120)
                .background(.yellow.opacity(0.6))

            Text("Offered Width is \(Int(width))")
            Slider(value: $width, in: 0...200, step: 5)
        }
    }
}

struct SubView: View {
    let desiredWidth: CGFloat
    var body: some View {
        Rectangle()
            .fill(.clear)
            .border(Color.blue, width: 2)
            .frame(width: desiredWidth, height: nil)
    }
}

在此示例中,SubView 具有黄色填充和最小框架宽度,而内部矩形仅采用滑块上设置的任何宽度。它也不再需要 GeometryReader 了。它的外观和行为相同,但 none 的视图不再超出其父级的范围。