1

I'm currently working on a rather simple view: a bunch of H/VStacks on top of each other using a ZStack. I'm constraining the size of my ZStack using the .frame modifier. For some reason my nested VStack seems to ignore its parent frame. What I want to achieve is that the VStack matches the frame of the ZStack in the same way that the Image does.

struct CourseTileView: View {
    let viewModel: CourseTileViewModel
    var body: some View {
        ZStack {
            Image(uiImage: viewModel.thumbnail)
                .resizable()
                .scaledToFill()
                .clipped()
            VStack {
                HStack {
                    HStack {
                        ForEach(viewModel.mediaTypes.sorted(), id: \.self) {
                            $0.image
                                .foregroundColor(.white)
                                .frame(width: 20, height: 20)
                        }
                    }
                    Spacer()
                    RedCapsuleTextView(title: "NEW")
                        .isHidden(!viewModel.isBadgeVisible)
                }
                Spacer()
                Text(viewModel.title)
                    .foregroundColor(.white)
                    .font(.mpText.bold())
                ProgressBar(
                    tintColor: .white,
                    backgroundColor: .white.alpha(0.3),
                    progress: viewModel.progress
                )
                .frame(width: 144, height: 7)
                .isHidden(viewModel.progress == .zero)
            }
            .padding()
        }
        .frame(width: 164, height: 270)
        .clipShape(RoundedRectangle(cornerRadius: 10))
    }
}

The blue border is the size of the VStack reported in the preview: enter image description here

Is it necessary to set a frame for the VStack as well?

Update

Using a GeometryReader would solve the problem, but... is that the way to go?

ZStack {
    GeometryReader { geometry in
        Image(uiImage: viewModel.thumbnail)
            .resizable()
            .scaledToFill()
            .clipped()
        VStack {
            // Content
        }
        .frame(maxWidth: geometry.size.width)
        .padding(.horizontal, Margin.small)
        .padding(.vertical, Margin.medium)
    }
    .frame(width: 164, height: 270)
    .clipShape(RoundedRectangle(cornerRadius: 10))
}
2
  • you want your Image and your content aka VStack respect to frame of (164X270) or what? which of those three things are the base for you? frame or Image or VStack? Commented Jul 30, 2021 at 11:45
  • I want the ZStack to be the base, therefore I'm setting the frame there. Every child view should respect ZStack's frame. Commented Jul 30, 2021 at 12:25

1 Answer 1

3

You might need to use overlay instead of a ZStack. This forces the overlaying view (your VStack) to constrain to the bottom view (your Image). Here's a simplified version of your code:

struct CourseTileViewModel {
    var title = "How to deal with stack overflow questions"
    var thumbnail = UIImage(named: "Image")!
}
struct ContentView21: View {
    let viewModel = CourseTileViewModel()
    var body: some View {
        Image(uiImage: viewModel.thumbnail)
            .resizable()
            .scaledToFill()
            .clipped()
            .frame(width: 164, height: 270)
            .clipShape(RoundedRectangle(cornerRadius: 10))
            
            /// overlay will be the exact same size as the image
            .overlay(
                VStack {
                    Spacer()
                    Text(viewModel.title)
                        .fontWeight(.bold)
                }
                .frame(maxWidth: .infinity) /// make it take up as much width as possible
                .padding()
                .border(Color.blue)
            )
            
    }
}

Result:

Overlaying text does not get cut off

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.