stephen
stephen

Reputation: 597

Is there a way to fix the button width in swiftUI?

I try to fix the button width in swiftUI, but whether the width is pointed in .frame(width: ) or fixed in .fixedSize(horizontal: true, vertical: false) modifiers, or both, it still doesn't work. The button is just shrink or expand by its content length. How can I solve it?

Pls see below the code & picture:

struct ContentView: View {
    var body: some View {
        let days = [0, 1, 2, 3, 4]
        
        let dayWeatherList = ["Sunday, Sunny",
                                  "Monday, Sunny",
                                  "Tuesday, Sunny",
                                  "Wednesday, Sunny",
                                  "Thursday, Sunny"]
        
        let aqiList = [aqiItem(aqi: 6, color: .green),
                               aqiItem(aqi: 123, color: .orange),
                               aqiItem(aqi: 25, color: .green),
                               aqiItem(aqi: 345, color: .red),
                               aqiItem(aqi: 56, color: .yellow)]
        
        VStack {
            ForEach(days, id: \.self) { index in
                let dayWeatherInfo = dayWeatherList[index]
                let aqiForecast = aqiList[index]
                ForecastDayView(dayWeatherInfo: dayWeatherInfo, aqiForecast: aqiForecast)
            }
        }
        .padding(24)

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct aqiItem {
    let aqi: Int
    let color: Color
}

struct ForecastDayView: View {
    let dayWeatherInfo: String
    let aqiForecast: aqiItem
    
    var body: some View {
        let fontSize: CGFloat = 14
        
        HStack(alignment: .center) {
            Text(dayWeatherInfo)
                .font(.system(size: fontSize))
                .fontWeight(.semibold)
                .foregroundColor(.black)
            
            Spacer()
            
            Text("24/32°")
                .font(.system(size: fontSize))
                .fontWeight(.semibold)
                .foregroundColor(.black)
            
            Spacer()
            
            HStack(spacing: 16) {
                if let aqiForecast = aqiForecast {
                    let aqi = aqiForecast.aqi
                    let color = aqiForecast.color
                    
                    Button(action: {}, label: {
                        Text("\(aqi)")
                            .foregroundColor(.white)
                            .padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4))
                    })
                    .font(.system(size: 13))
                    .background(color)
                    .cornerRadius(4)
                    .frame(width:40)
                    .fixedSize(horizontal: true, vertical: false)
                }
                
                let length: CGFloat = 18
                
                Image("100")
                    .resizable()
                    .frame(width: length, height: length)
                
                Image("101")
                    .resizable()
                    .frame(width: length, height: length)
            }
            
        }
    }
    
}

Buttons have different width: enter image description here

Thanks very much in advance!

Upvotes: 11

Views: 11388

Answers (3)

davidev
davidev

Reputation: 8547

You are applying .background before you set the width. If you first apply .frame(width: 40) and then set the background color, you will see everything has the same size.

Button(action: {}, label: {
    Text("\(aqi)")
        .foregroundColor(.white)
        .padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4))
})
.frame(width:40)
.font(.system(size: 13))
.background(color)
.cornerRadius(4)

Upvotes: 15

DILIP KOSURI
DILIP KOSURI

Reputation: 465

You can keep it look cleaner by doing it in the following way:

    struct ContentView: View {
    var body: some View {
        let days = [0, 1, 2, 3, 4]
        
        let aqiList = [aqiItem(aqi: 6, color: .green),
                       aqiItem(aqi: 123, color: .orange),
                       aqiItem(aqi: 25, color: .green),
                       aqiItem(aqi: 345, color: .red),
                       aqiItem(aqi: 56, color: .yellow)]
        
        let dayWeatherList = ["Sunday, Sunny",
                              "Monday, Sunny",
                              "Tuesday, Sunny",
                              "Wednesday, Sunny",
                              "Thursday, Sunny"]
        
        VStack {
            ForEach(days, id: \.self) { index in
                let dayWeatherInfo = dayWeatherList[index]
                let aqiForecast = aqiList[index]
                ForecastDayView(dayWeatherInfo: dayWeatherInfo, aqiForecast: aqiForecast)
            }
        }
        .padding(24)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct aqiItem {
    let aqi: Int
    let color: Color
}

struct ForecastDayView: View {
    let dayWeatherInfo: String
    let aqiForecast: aqiItem
    let length: CGFloat = 18
    
    private var images: some View {
        HStack { // Can use Group as well
            Image("100")
                .resizable()
                .frame(width: length, height: length)
            
            Image("101")
                .resizable()
                .frame(width: length, height: length)
        }
    }
    
    private var forecastView: some View {
        HStack { // Can use Group as well
            VStack {
                Text(dayWeatherInfo)
                    .font(.system(size: 14))
                    .fontWeight(.semibold)
                    .foregroundColor(.black)
            }
            .frame(minWidth: 0, maxWidth: .infinity)
            
            VStack {
                Text("24/32°")
                    .font(.system(size: 14))
                    .fontWeight(.semibold)
                    .foregroundColor(.black)
            }
            .frame(minWidth: 0, maxWidth: .infinity)
        }
    }
    
    var body: some View {
        HStack(spacing: 0) {
            
            forecastView[![enter image description here][1]][1]
            
            if let aqiForecast = aqiForecast {
                let aqi = aqiForecast.aqi
                let color = aqiForecast.color
                VStack {
                    Button(action: {}, label: {
                        Text("\(aqi)")
                            .foregroundColor(.white)
                            .padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4))
                    })
                    .font(.system(size: 13))
                    .cornerRadius(4)
                }
                .frame(minWidth: 0, maxWidth: .infinity)
                .background(color)
            }
            
            images
        }
    }
}

enter image description here

Upvotes: 0

mahan
mahan

Reputation: 15035

Order of modifiers is important. This link may help you.

https://www.hackingwithswift.com/books/ios-swiftui/why-modifier-order-matters


Do as davidev has suggested or use .frame(minWidth:40) on Text and remove its horizontal padding.

                Button(action: {}, label: {
                    Text("\(aqi)")
                        .foregroundColor(.white)
                        .padding(.vertical, 2)
                        .frame(minWidth:40)
                })
                .font(.system(size: 13))
                .background(color)
                .cornerRadius(4)

Upvotes: 1

Related Questions