Reputation: 597
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)
}
}
}
}
Thanks very much in advance!
Upvotes: 11
Views: 11388
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
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
}
}
}
Upvotes: 0
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