在 ZStack 内部定位

eug*_*prg 1 swiftui swiftui-zstack

我希望将这个红色矩形重新定位到左下角,但由于某种原因,我的对齐和填充没有按预期工作。我在做什么错以及如何将其移动到左下角?

代码:

struct ContentView: View {
    
    var body: some View {

        ZStack {
                VStack(spacing: 0) {
                    Rectangle()
                        .fill(Color.red)
                        .frame(width: 197, height: 163)
                }
                .frame(width: 284, height: 269)
                .padding(.leading, 0)
                .padding(.bottom, 0)
                .background(Color.blue)
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

Yod*_*ama 9

ZStack 有一个参数alignment: Alignment,它是两个轴上的对齐方式。

  struct ContentView: View {
        
        var body: some View {
            
            ZStack(alignment:.bottomLeading) {
                Rectangle()
                    .fill(Color.blue)
                    .frame(width: 284, height: 269)
                Rectangle()
                    .fill(Color.red)
                    .frame(width: 197, height: 163)
            }
            
            
        }
    }
Run Code Online (Sandbox Code Playgroud)


Rob*_*ier 5

Yodagama 的答案可能是您想要的,但也值得探索您的困惑,因为 SwiftUI 布局并不像您认为的那样工作。调用 like.frame(...)不会“设置项目的大小”,.fill(...)也不会“设置项目的颜色”。SwiftUI 中的几乎所有内容都创建了一个全新的 View,它负责放置其子项。在许多情况下,这些感觉就像是同一件事,但它们非常不同。

我将分解您的代码中发生的事情,从内部开始并进行锻炼。

                Rectangle()
Run Code Online (Sandbox Code Playgroud)

这将创建一个 Rectangle 来填充它给定的任何空间。

                Rectangle()
                    .fill(Color.blue)
Run Code Online (Sandbox Code Playgroud)

这会将 Rectangle 嵌入到一个新的 View 中,该 View 将环境中的“填充”颜色设置为蓝色。

                Rectangle()
                    .fill(Color.blue)
                    .frame(width: 197, height: 163)
Run Code Online (Sandbox Code Playgroud)

这会将其嵌入到具有固定大小 (197x163) 的新视图中。嵌入的 View 居中,但由于 Rectangle 占用了所有可用空间,因此它填充了 Frame。

            VStack(spacing: 0) {
                Rectangle()
                    .fill(Color.red)
                    .frame(width: 197, height: 163)
            }
Run Code Online (Sandbox Code Playgroud)

这将该 Frame 嵌入到一个 VStack 中,该 VStack 在其元素之间没有间距(但这并不重要,因为只有一个)。VStack 正好是它的孩子的大小 (197x163)。

            VStack(spacing: 0) {
                Rectangle()
                    .fill(Color.red)
                    .frame(width: 197, height: 163)
            }
            .frame(width: 284, height: 269)
Run Code Online (Sandbox Code Playgroud)

这将 197x163 VStack 集中在一个固定为 284x269 的新视图中。它并没有在VStack的大小设置为284x269。VStacks 总是正好是他们孩子的大小。这是您出错的具体地方(我将在完成其余部分后解释如何修复它)。

            VStack(spacing: 0) {
                Rectangle()
                    .fill(Color.red)
                    .frame(width: 197, height: 163)
            }
            .frame(width: 284, height: 269)
            .padding(.leading, 0)
            .padding(.bottom, 0)
Run Code Online (Sandbox Code Playgroud)

这将创建一个新视图,该视图嵌入 284x269 帧,左侧有 0 个额外填充(因此这个新视图与当前帧的大小完全相同,并且什么也不做)。然后将其嵌入到一个新的 View 中,在底部添加 0 个额外的填充。同样,这根本没有任何作用。

           VStack(spacing: 0) {
                Rectangle()
                    .fill(Color.red)
                    .frame(width: 197, height: 163)
            }
            .frame(width: 284, height: 269)
            .padding(.leading, 0)
            .padding(.bottom, 0)
            .background(Color.blue)
Run Code Online (Sandbox Code Playgroud)

这将所有这些嵌入到一个新的 View 中,该 View 绘制一个与嵌入的 View (284x269) 大小完全相同的蓝色背景。

    ZStack {
            VStack(spacing: 0) {
                Rectangle()
                    .fill(Color.red)
                    .frame(width: 197, height: 163)
            }
            .frame(width: 284, height: 269)
            .padding(.leading, 0)
            .padding(.bottom, 0)
            .background(Color.blue)
        }
}
Run Code Online (Sandbox Code Playgroud)

最后,这一切都集中在 ZStack 中。ZStack 正是包装其子项所需的大小,因此是 284x269。这根本没有任何作用。


那么你如何解决这个问题。您出错的地方是 VStack 在其周围 Frame 中的定位方式。它居中,但您希望它对齐。这里不需要 ZStack,甚至不需要 VStack。你这样做:

    Rectangle()
        .fill(Color.red)
        .frame(width: 197, height: 163)
        .frame(width: 284, height: 269, alignment: .bottomLeading) // <===
        .background(Color.blue)
Run Code Online (Sandbox Code Playgroud)

注意两个框架视图是如何连续创建的。第一个边界矩形。第二个将其嵌入并对齐到更大的框架中。这是 SwiftUI 与开发人员想象的如此不同的一个很好的例子。事实上,这可以进一步简化,因为颜色填充了它提供的所有空间,就像矩形一样:

    Color.red
        .frame(width: 197, height: 163)
        .frame(width: 284, height: 269, alignment: .bottomLeading)
        .background(Color.blue)
Run Code Online (Sandbox Code Playgroud)

但我经常发现,如果可能,使用 Spacers 会做得更好,也更灵活。根据我的经验,当您没有固定的框架尺寸时,垫片会更好地工作。(我并不是说这一定是最佳实践;这只是我的经验。SwiftUI 非常新,我们仍在弄清楚最佳实践是什么。)

    VStack {
        Spacer()    // Fill all space above
        HStack {
            Rectangle()
                .fill(Color.red)
                .frame(width: 197, height: 163)
            Spacer()    // Fill all space to the right
        }
    }
    .frame(width: 284, height: 269)
    .background(Color.blue)
Run Code Online (Sandbox Code Playgroud)

  • Rob,感谢您花时间和精力向我解释这一点,这让我在理解 swiftui 的工作原理方面又迈出了一步 (2认同)