So I want to have a dropdown containing different categories and each category should have a color, the string value of the category should be binded to my viewmodel.category.
This is what I have:
View:
Picker("Category", selection: $viewModel.category) {
ForEach(Category.allCases, id: \.self) { category in
CategoryView(category: category)
.tag(category.rawValue)
}
}
Category View:
struct CategoryView: View {
let category: Category
var body: some View {
HStack {
Text(category.rawValue.capitalized)
Circle()
.fill(category.color)
.frame(width: 20, height: 20)
.padding(.trailing, 8)
}
}
}
Category Model:
enum Category: String, CaseIterable {
case groceries
case utilities
case transportation
case entertainment
var color: Color {
switch self {
case .groceries:
return Color.blue
case .utilities:
return Color.green
case .transportation:
return Color.orange
case .entertainment:
return Color.purple
}
}
}
The dropdown shows the categories just fine, but with no circle for color:
Also, if I put just a categoryview hardcoded in the view, like this:
CategoryView(category: .entertainment)
It shows up fine:
Any ideas?
The answer to SwiftUI Picker issue with Rectangle() instead of Text() shows how this can be done (it was my answer):
Color
to an Image
Picker
using Labels
that in turn are built using the name of the category and the color Image
.Actually, it works to build the label using your CategoryView
, but it is only the text part that gets used, so you might as well use the Text
directly.
Like this:
private func colorImage(color: Color) -> Image {
Image(size: CGSize(width: 26, height: 20)) { ctx in // includes trailing padding
ctx.fill(
Path(ellipseIn: CGRect(origin: .zero, size: CGSize(width: 20, height: 20))),
with: .color(color)
)
}
}
var body: some View {
Form {
Picker("Category", selection: $viewModel.category) {
ForEach(Category.allCases, id: \.self) { category in
Label(
title: { Text(category.rawValue.capitalized) },
icon: { colorImage(color: category.color) }
)
.tag(category.rawValue)
}
}
}
}