How can I modify layout to have a custom variable aspect ratio, or width never higher than height

I created a small component using a Text and optionally an Image, inside an HStack. Then I apply padding and clipping using a Capsule shape.

Below you have the code and the results.

The problem I have is that I want to constraint the component in a way that the width is always equal or higher than its height. That is, a vertical capsule is not allowed, only an horizontal capsule or a circle.

I tried different approaches. For example, measure the component size using Geometry reader. We can use the .measure modifier, which basically puts everything inside .background and applies a Geometry Reader, and moves the value up using Preference Keys. Measure modifier: swiftuirecipes.com/blog/getting-size-of-a-view-in-swiftui

But it does not work, looks like the HStack is returning zero, or causing issues.

In any case, I was told to avoid GeometryReader whenever possible. What other approaches I could follow?

There must be a way playing with .background and .layoutPriority, butI don't know exactly how to do it.

Would be nice to have something like an .aspectRatio modifier where we can pass something like "1 or higher", but I have no idea about how to implement that.

Do you have any idea or suggestion? Thanks a lot.

[![enter image description here][1]][1]

struct ContentView: View {
    var body: some View {
        VStack(spacing: 20) {
            Label(text: "2", showIcon: true)
            Label(text: "99+", showIcon: true)
            Label(text: "1", showIcon: false) // Case to fix
        }
    }
}

struct Label: View {

    let text: String
    let showIcon: Bool

    var body: some View {
            HStack {
                if showIcon {
                    Image(systemName: "bolt")
                        .resizable()
                        .frame(width: 15, height: 15)
                }
                Text(text)
            }
            .padding(4)
            .background(Color.red)
            .clipShape(Capsule())
    }
}

Replies

I just replaced:

            .background(Color.red)
            .clipShape(Capsule())

with

        .frame(minWidth: 30)    // That's the height of Label
        .background(Capsule().fill(Color.red))
struct Label: View {
    
    let text: String
    let showIcon: Bool
    
    var body: some View {
        HStack {
            if showIcon {
                Image(systemName: "bolt")
                    .resizable()
                    .frame(width: 15, height: 15)
            }
            Text(text)
        }
        .padding(4)
        .frame(minWidth: 30)
        .background(Capsule().fill(Color.red))
    }
}

And got this:

">

">