Search code examples
swiftuivertical-alignment

TopTrailing alignment is not working when trying to position the vStack inside of zStack


I am new to SwiftUI. I am trying to create a view like heart card but not being able to place the vStack of heart and letter at the top-right(topTrailing) corner of the rectangle.

var body: some View {
    ZStack {
        RoundedRectangle(cornerRadius: 5.0)
            .fill(.white)
            .stroke(.gray, style: StrokeStyle(lineWidth: 2.0))
            .frame(width: 100, height: 150)
            .shadow(color: Color(.black).opacity(0.3), radius: 5)
        
        VStack(spacing: 0) {
            Text("A")
                .font(.callout)
            
            Image(systemName: "heart.fill")
                .resizable()
                .frame(width: 10, height: 10)
        }.frame(alignment: .topTrailing)
    }
}

here is what I get as output. enter image description here

Can someone please help.


Solution

  • If you add a border to the VStack, you can see how the content of the VStack completely fills its frame:

    VStack(spacing: 0) {
        // as before
    }
    .frame(alignment: .topTrailing)
    .border(.orange)
    

    Screenshot

    What this .frame modifier is doing is to align the content of the VStack within a frame of the same size. But since the content already fills the frame, it makes no difference.

    With these changes it can be made to work:

    • Move the .frame modifier that sets the size of the card from the RoundedRectangle to the ZStack that contains all the content.

    • Add maxWidth: .infinity, maxHeight: .infinity to the .frame modifier being set on the VStack, so that the frame expands to use all of the space available.

    • You might like to add a bit of padding to the VStack too.

    ZStack {
        RoundedRectangle(cornerRadius: 5.0)
            // as before, but without .frame
    
        VStack(spacing: 0) {
            // as before
        }
        .padding(8) // <- ADDED
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing) // <- maxWidth and maxHeight added
    }
    .frame(width: 100, height: 150) // <- moved from RoundedRectangle
    

    So what this does is to fix the size of the ZStack to the card size. A RoundedRectangle (like any Shape) is greedy, so it expands to fill the same space. The .frame modifier on the VStack now causes it to expand to the size of the ZStack and the alignment parameter aligns the content as you intended it to.

    Screenshow or with a border on the VStack: enter image description here