Home > Enterprise >  Why does Image overlap the view above it in a SwiftUI VStack?
Why does Image overlap the view above it in a SwiftUI VStack?

Time:09-26

I am trying to guarantee that regardless of the image's dimensions, it won't overlap its neighbor sitting above it vertically.

enter image description here

Here is the code I used.

import SwiftUI

struct CardDetailView: View {
    
    var body: some View {
        ZStack {
            Color.black
                .edgesIgnoringSafeArea(.all)
            Image(.darkColorShade)
                .resizable()
                .edgesIgnoringSafeArea(.all)
            ScrollView {
                VStack {
                    Text("Two of Cups".capitalized)
                        .font(.largeTitle)
                        .foregroundColor(.white)
                   // Spacer(minLength: 100)
                    Image(uiImage: .cardDemo)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(width: 170, height: 150)
                        
                }
            }
        }
    }
}

struct CardDetailView_Previews: PreviewProvider {
    static var previews: some View {
        CardDetailView()
    }
}

When I uncomment the Spacer, it adjusts to the location I want. The Image should appear vertically below the text because it comes after the text in a VStack.

enter image description here

When the spacer is commented, the image overlaps its neighbor if its frame width exceeds its height. Why is that?

I am just trying to produce a predictable and reliable space between two different views. I shouldn't just tweak it to appear correct without understanding what is happening. I also tried setting the background of Image View to red, but that didn't give me any clues to what was happening.

CodePudding user response:

Why does Image overlap the view above it in a SwiftUI VStack?

The image is overflowing its frame. Notice that your frame is wider than it is tall:

Image(uiImage: .cardDemo)
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: 170, height: 150)

But it doesn’t look that way onscreen. The image is oozing over the top and bottom of the frame. This is what .aspectRatio(contentMode: .fill) does. It scales the original image proportionally until it fills the frame in each direction overflowing the frame in one direction if necessary.

If you add:

    .clipped()

It will clip the parts that fall outside of the frame. Then it will not overlap the objects above it and below it.


How can I ensure the image maintains a certain width and height proportion?

Use .aspectRatio(contentMode: .fit) or .scaledToFit() along with a frame that specifies only the width or the height. SwiftUI will calculate the other dimension of the frame to maintain the image proportions (aspect ratio).

Image(uiImage: .cardDemo)
    .resizable()
    .scaledToFit()
    .frame(width: 170)

CodePudding user response:

Using a spacer will try to use all of the space given to that view. My best fix for this would be to manually put a specific amount of padding. For example, under the Image(uiImage: .cardDemo) you could put .padding(.top, 75), and that would add some space between Two of Cups.

Hope I helped :)

  • Related