Home > other >  Unexpected layout issues with SwiftUI Image and ZStack
Unexpected layout issues with SwiftUI Image and ZStack

Time:06-12

I'm trying to create a view composed of two parts - the top part is an image with a piece of text overlaid in the top left corner. The top part should take up 2/3 of the height of the view. The bottom part is text information and a button, contained in an HStack, and takes up the remaining 1/3 of the view height.

struct MainView: View {
    var body: some View {
        GeometryReader { gr in
            VStack(spacing: 0) {
                ImageInfoView()
                    .frame(height: gr.size.height * 0.66)
                BottomInfoView()
            }
            .clipShape(RoundedRectangle(cornerRadius: 20))
        }
    }
}

struct ImageInfoView: View {

    var body: some View {
        ZStack(alignment: .topLeading) {
            Image("testImage")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .overlay(Rectangle()
                    .fill(Color.black.opacity(0.5))
                )
            
            HStack {
                Text("Top left text")
                    .foregroundColor(.white)
                    .padding()
            }
        }
    }
}

struct BottomInfoView: View {

    var body: some View {
        HStack {
            VStack(alignment:.leading) {
                Text("Some title")
                Text("Some subtitle")
            }
            
            Spacer()
            Button("BUTTON") {
            }
        }
        .padding()
        .background(.gray)
    }
}

In the below sample code, if I set the frame height to 400 I will see the top left text, but when I set it to 200, I do not. What is happening here? The text should be anchored to the top left corner of ImageInfoView no matter what. Further, when set to 400, why does the ImageInfoView take up more than 66% of the height?

struct TestView: View {
    var body: some View {
        MainView()
            .frame(height: 200)
            .padding([.leading, .trailing], 16)
    }
}

height 400 height 200

CodePudding user response:

An image's fill pushes ZStack boundaries, so Text goes off screen (see demo

    ZStack(alignment: .topLeading) {
        Color.clear.overlay(    // << here !!
            Image("testImage")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .overlay(Rectangle()
                    .fill(Color.black.opacity(0.5))
                )
        )
        // ... other code as-is

CodePudding user response:

This fixes the problem:

ZStack(alignment: .topLeading) {
    GeometryReader { gr in
         Image("testImage")
             .resizable()
             .aspectRatio(contentMode: .fill)
             .frame(maxWidth: gr.size.width, maxHeight: gr.size.height)
             .overlay(Rectangle()
                  .fill(Color.black.opacity(0.5))
             )
                    
         HStack {
             Text("Top left text")
                 .foregroundColor(.white)
                 .padding()
             }
         }
     }
}
  • Related