【问题标题】:SwiftUI: Can't align image to the top of ZStackSwiftUI:无法将图像对齐到 ZStack 的顶部
【发布时间】:2020-01-24 20:39:58
【问题描述】:

我不知道如何在ZStack 之上对齐Image 视图,默认情况下,SwiftUI 中的视图放置在其父视图的中心,然后我们使用堆栈来对齐它们,我有以下一段代码:

struct ContentView: View {
    var body: some View {
        ZStack {
           Image("bgImage")
           Text("Hello, World!")
        }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.red) //this is for debugging purposes, to show the area of the ZStack
    }
}

如何将图像定位到顶部?

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    要告诉 ZStack 在其中以特定方式对齐事物,请使用 alignment 参数对其进行配置:

    ZStack(alignment: .top) {
        Color.clear
        Image(...)
        Text("Hello, World!")
    }
    

    (Color.clear 扩展以填充所有可用空间,因此这会强制您的 ZStack 与封闭视图一样大,而无需添加 .frame()。)

    当然,这会将所有内容对齐在顶部,这可能不是您想要的。你可以通过嵌套你的 ZStack 来解决这个问题:

    ZStack{
        ZStack(alignment: .top) {
            Color.clear
            Image(...)        // This will be at the top
        }
        Text("Hello, World!") // This will be centered
    }
    

    也就是说,我可能会在此示例中使用.background

    ZStack {
        Color.clear
        Text("Hello, World!")
    }
    .background(Image(...), alignment: .top)
    

    如果你只有一个视图,你可以去掉 ZStack 并使用框架:

    Text("Hello, World!")
        .frame(maxHeight: .infinity)
        .background(Image(uiImage:#imageLiteral(resourceName: "image.jpg")), 
                    alignment: .top)
    

    请记住,在这种情况下,图像将绘制在其框架之外。在许多情况下这很好(而且它完全合法),但有时它可能很重要(例如,如果你把它放在一个堆栈中)。您可以在末尾添加.border(Color.green) 以查看其工作原理。


    这个示例真正触及了 SwiftUI 布局的核心,因此值得了解发生了什么。这不是解决方法或技巧,所以你应该去感觉很正常的地方。

    顶级内容视图(包含 ZStack 的视图)将其整个空间提供给 ZStack。 ZStack 的大小始终与包含其内容的大小完全相同,因此首先 ZStack 需要对其子项进行布局。它根据对齐方式对它们进行布局,然后精确调整自身大小以适应它们。因此,使用顶部对齐(但没有 Color.clear),图像位于 ZStack 的顶部。 ZStack 与 Image 的大小完全相同。

    然后,顶级内容视图将 ZStack 置于其中心。

    ZStack 布置其子项的方式与内容视图的方式类似。它提供了它所提供的所有空间,然后子视图决定它们的大小。 视图始终决定自己的大小。 Image 和 Text 是固定大小的视图,因此它们只是其内容的大小。但是 Color 是一个灵活大小的视图。它接受 ZStack 提供的整个空间(与顶级内容视图提供的空间相同)并将其作为其大小返回。由于 ZStack 必须准确地包含其子项,因此 ZStack 现在是顶级内容视图的大小,并且事情的行为与您预期的一样,在屏幕顶部对齐。

    让我们与您最初使用.frame() 进行比较:

    ZStack {
       Image("bgImage")
       Text("Hello, World!")
    }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    .background(Color.red) //this is for debugging purposes, to show the area of the ZStack
    

    首先,我想重点关注您的评论,因为它不正确。这不是 ZStack 的区域。 ZStack 正是其内容(图像和文本)的大小。你把背景放在框架视图上,框架视图就大了。

    人们的一个主要困惑是他们认为.frame(...) 改变了它所附加的视图的大小。这根本不正确。和以前一样,ZStack 始终是其内容的大小。 .frame() 创建一个请求大小的全新视图。然后它根据框架的对齐方式将包裹的视图定位在自身内部。所以在这个例子中它是这样工作的:

    顶层 - 背景 - 框架 - ZStack - {图像文本}

    顶层视图将其所有空间提供给背景。背景是它们所包含内容的大小,因此它为框架提供了所有空间。 Frame 在两个方向上都是灵活的(由于 max 字段),因此它会忽略其子项的大小并选择提供给它的大小。

    Frame 然后将所有空间提供给 ZStack。 ZStack 布置其子级,并返回其大小与包含它们的大小完全相同。

    Frame 然后根据 Frame 的对齐方式放置 ZStack(.center,因为这是默认设置)。如果您将 Frame 的对齐方式设置为 .top,那么 ZStack 将被放置在框架的顶部(但文本将在 ZStack 中而不是在 Frame 中居中)。

    然后它向后台报告它与顶级视图一样大(因为它很灵活)。

    背景然后声明与顶级内容视图相同的大小。

    最后,顶级内容视图将背景置于其中心。

    【讨论】:

    • 我只是想了解第一个代码sn-p,为什么ZStack不使用Color视图不将其内容对齐到顶部?您在上面说过Color 视图放大了ZStack 以扩展父视图中的所有可用空间,对于来自UIKit 世界的新人来说,这有点奇怪。
    • 感谢您的详尽解释,现在我了解了在 SwiftUI 中的布局过程中视图如何相互通信的基础知识,这与 UIKit 完全不同。非常感谢。
    • 我希望我能支持你的回答 10 次 :} 它为我澄清了这么多晦涩的问题!谢谢!
    【解决方案2】:

    所以对你不利的一件事是 infinity maxHeight 修饰符,假设你不希望图像和视图底部之间有一些空间。

    .edgesIgnoringSafeArea(.all)
    

    您可能只需要告诉您的 ZStack 忽略安全区域插入。

    struct ContactsView: View {
      var body: some View {
    
        ZStack {
          Image("bgImage")
          Text("Hello, World!")
        }.frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red).edgesIgnoringSafeArea(.all)
    
      }
    }
    

    如果底部和图像之间需要空间,请将 ZStack 包裹在 VStack 中,并在 VStack 底部放置 Spacer。

    struct ContactsView: View {
      var body: some View {
        VStack {
    
          ZStack {
            Image(systemName: "bgImage")
            Text("Hello, World!")
          }.frame(maxWidth: .infinity, maxHeight: 300).background(Color.red)
    
          Spacer()
    
        }.edgesIgnoringSafeArea(.all)
      }
    }
    

    【讨论】:

      【解决方案3】:
      ZStack {
          Image("background")
               .resizable()
               .scaledToFill()
               .edgesIgnoringSafeArea(.all)
      }
      

      添加 .edgesIgnoringSafeArea(.all)

      【讨论】:

      • 看来你误解了这个问题。
      猜你喜欢
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 2012-05-03
      • 2022-08-23
      • 2020-10-04
      • 1970-01-01
      • 2021-07-24
      • 2020-09-10
      相关资源
      最近更新 更多