Home > Enterprise >  Have a VStack with a square background depending on its content in SwiftUI
Have a VStack with a square background depending on its content in SwiftUI

Time:10-23

I'm running into a kind of a conundrum with a seemingly simple problem...

My view has a content with a smaller width than height, and I wish to have it displayed within a nice square card.

Here's what I've done here:

struct SquareView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .font(.system(size: 100))
                .padding()
                .foregroundColor(.red)
            Text("Yo !")
                .font(.title)
                .fontWeight(.bold)
                .foregroundColor(.orange)
        }
        .aspectRatio(contentMode: .fill) // Same result with or without this line
        .padding()
        .background(Color.white.opacity(0.5))
        .cornerRadius(16)
    }
}

struct SquareView_Previews: PreviewProvider {
    static var previews: some View {
        SquareView()
            .padding(30)
            .background(.yellow)
    }
}

But the aspectRatio bit seems to have absolutely no effect on the square part I wish to achieve.

First attempt

After looking up for a solution, it seems that ZStack was to be my savior...

Ok, then, here's what I did, and I almost succeeded:

struct SquareView: View {
    var body: some View {
        ZStack {
            Rectangle()
                .foregroundColor(Color.white.opacity(0.5))
                .aspectRatio(contentMode: .fill)
                .cornerRadius(16)
            VStack {
                Image(systemName: "globe")
                    .font(.system(size: 100))
                    .padding()
                    .foregroundColor(.red)
                Text("Yo !")
                    .font(.title)
                    .fontWeight(.bold)
                    .foregroundColor(.orange)
            }
            .padding()
        }
        .fixedSize()
    }
}

And lo!

Second attempt

It's square, all right, but the size of the ZStack does not seem to take into account the Rectangle, as it is confirmed when it is selected in Xcode:

ZStack selection

So the only solution seems to be one involving GeometryReader and pride makes me refuse this remain of the old age!

I'm sure, someone out there knows there is another way, I'm certain to be quite close... Any help on this matter would be greatly appreciated!

EDIT: I've put the whole file in the example, instead of just the content.

EDIT 2: Here's the complete solution for my example thanks to @Paulw11's answer.

struct SquareView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .font(.system(size: 100))
                .padding()
                .foregroundColor(.red)
            Text("Yo !")
                .font(.title)
                .fontWeight(.bold)
                .foregroundColor(.orange)
        }
        .padding()
        .background {
            Rectangle()
                .aspectRatio(contentMode: .fill)
                .foregroundColor(.white.opacity(0.5))
                .cornerRadius(16)
        }
    }
}

And its result: enter image description here

CodePudding user response:

You can simply set a background for your existing content and give it a negative inset:

struct CardView: View {
    var body: some View {
       ContentView()
          .background(
               Rectangle()
                .inset(by:-30)
                .aspectRatio(1.0, contentMode:.fill)
                .foregroundColor(.yellow)
          ) 
        }
    }

enter image description here

  • Related