Home > Blockchain >  How to create two "squares" with same size taking up whole screen width in SwiftUI?
How to create two "squares" with same size taking up whole screen width in SwiftUI?

Time:10-08

I'm trying to build the subscription price info boxes like the screenshot below. How can I achieve these boxes to be square and take up the full width of the screen (minus spacing)

Subscription pricing

(Just to be clear, I'm interested in how two boxes can be square and take their height values from screen size automatically. I'm not interested in full design as it will be handled after achieving the box sizes) So far what I tried is like below:

This is for individual boxes:

struct SubscriptionPriceBox: View {
let title: String
let duration: String
let price: String
let renewInfo: String

var body: some View {
    ZStack(alignment: .top) {
        VStack {
            VStack {
                Text(duration)
                Text(price)
            }
            Text(renewInfo)
        }
        .overlay {
            RoundedRectangle(cornerRadius: 2)
                .stroke(.gray, lineWidth: 2)
        }
        .aspectRatio(1, contentMode: .fit)
        .frame(maxWidth: .infinity)
        
        Text(title)
            .background(Color.yellow)
            .offset(x: -20, y: -10)
    }
    .background(Color.red)
}

And this code is the container view for them:

var body: some View {
    VStack {
            HStack(alignment: .center) {
            SubscriptionPriceBox(title: "Basic Price",
                                 duration: "Monthly",
                                 price: "2.49$ / month",
                                 renewInfo: "Renew every month")
            SubscriptionPriceBox(title: "Save 33%",
                                 duration: "Annual",
                                 price: "19.99$ / month",
                                 renewInfo: "Renew every year")
        }.fixedSize(horizontal: true, vertical: false)

I think using GeometryReader is one option but couldn't figure that out completely. Also if there is a way to achieve this without using GeometryReader, I'm curious to learn it.

CodePudding user response:

You were close, you can use a LazyVGrid to make sure the view is always 2 columns then use the GeometryReader to match the sizes

        import SwiftUI

    struct boxProblem: View {
        
        private let gridItemLayout = Array(repeating: GridItem(.flexible(), spacing: 10), count: 2)
        
        var body: some View {
            VStack {
                LazyVGrid(columns: gridItemLayout) {
                    SubscriptionPriceBox(title: "Basic Price",
                                         duration: "Monthly",
                                         price: "2.49$ / month",
                                         renewInfo: "Renew every month")
                    SubscriptionPriceBox(title: "Save 33%",
                                         duration: "Annual",
                                         price: "19.99$ / month",
                                         renewInfo: "Renew every year")
                }
                .padding(.horizontal)
            }
        }
    }

    struct SubscriptionPriceBox: View {
        let title: String
        let duration: String
        let price: String
        let renewInfo: String
        
        var body: some View {
            GeometryReader { geometry in
                ZStack(alignment: .topLeading) {
                    
                    VStack {
                        VStack {
                            Text(duration)
                            Text(price)
                        }
                        Text(renewInfo)
                    }
                    .frame(maxWidth: .infinity)
                    .frame(height: geometry.size.width)
                    .overlay {
                        RoundedRectangle(cornerRadius: 2)
                            .stroke(.gray, lineWidth: 2)
                    }
                    Text(title)
                        .background(Color.yellow)
                        .offset(x: -20, y: -10)
                }
                .background(Color.red)
            }
        }
    }

enter image description here

  • Related