Search code examples
swiftswiftuifrontendspacing

SwiftUI: how to make a view fit into a certain size


So basically I have this view in my app. enter image description here

I want the box named LaMarcus Aldridge be the same size as the rest Basically I want to reduce the size of the box by reducing the amount of space between the picture and lines of text so that all boxes are the same size. I originally thought about going about it mathematically by calculating the space needed, but I am pretty sure that there is better way to do this that I am just no thinking of. Thank you I really appreciate it.

Here is the code that declared those boxes.

var body: some View {
        VStack(spacing: 15) { //first
            Image(uiImage: question.players[0].picture)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(height: 140)
//                .padding(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
            
            Text(question.players[0].name)
                .font(.title2)
                .fontWeight(.heavy)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
                .lineLimit(2)
            
            Text(question.players[0].team)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
        }
        .padding()
        .frame(maxWidth: .infinity)
        .onTapGesture(perform: {
            selectedAnswer = question.players[0]
        })
        
        .background(
            RoundedRectangle(cornerRadius: 15)
                .stroke(color(option: question.players[0]), lineWidth: 5)
        )
        .cornerRadius(15)
        
        VStack(spacing: 15) { //second
            Image(uiImage: question.players[1].picture)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(height: 140)
            Text(question.players[1].name)
                .font(.title2)
                .fontWeight(.heavy)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
                .lineLimit(2)
            
            Text(question.players[1].team)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
        }
        
        .padding()
        .frame(maxWidth: .infinity)
        .onTapGesture(perform: {
            selectedAnswer = question.players[1]
        })
        .background(
            RoundedRectangle(cornerRadius: 15)
                .stroke(color(option: question.players[1]), lineWidth: 5)
        )
        .cornerRadius(15)
        
        VStack(spacing: 15) { //third
            Image(uiImage: question.players[2].picture)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(height: 140)
            Text(question.players[2].name)
                .font(.title2)
                .fontWeight(.heavy)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
                .lineLimit(2)
            
            Text(question.players[2].team)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
        }
        
        .padding()
        .frame(maxWidth: .infinity)
        .onTapGesture(perform: {
            selectedAnswer = question.players[2]
        })
        .background(
            RoundedRectangle(cornerRadius: 15)
                .stroke(color(option: question.players[2]), lineWidth: 5)
        )
        .cornerRadius(15)
        
        VStack(spacing: 15) { //fourth
            Image(uiImage: question.players[3].picture)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(height: 140)
            Text(question.players[3].name)
                .font(.title2)
                .fontWeight(.heavy)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
                .lineLimit(2)
            
            Text(question.players[3].team)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
        }
        
        .padding()
        .frame(maxWidth: .infinity)
        .onTapGesture(perform: {
            selectedAnswer = question.players[3]
        })
        .background(
            RoundedRectangle(cornerRadius: 15)
                .stroke(color(option: question.players[3]), lineWidth: 5)
        )
        .cornerRadius(15)
    }

Solution

  • Try to use conditional in VStack. I've created a custom card view that you can use in your content view, with LazyVGrid + ForEach or simply with HStack and VStack.

    struct CardView: View{
    var playerName: String
    var playerTeam: String
    var playerPortrait: UIImage
    var body: some 
    View{
     
    //Control amount of spacing depend on amount of character in player's name
    VStack(spacing: playerName.count  > 13 ? -12 : 0) { //first
        Image(uiImage: playerPortrait)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(height:160)
                    .padding(10)
                
                Text(playerName)
                    .foregroundColor(.black)
                    .multilineTextAlignment(.center)
                    .lineLimit(2)
                    .padding(5)
                
                Text(playerTeam)
                    .foregroundColor(.black)
                    .multilineTextAlignment(.center)
                    .padding(5)
    }.background(RoundedRectangle(cornerRadius: 15).stroke()).padding(5)
    }
    }