iosswiftuipickerviewuicolor

Swift Picker Containing A View Not Showing The Color component


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:

Screenshot

Also, if I put just a categoryview hardcoded in the view, like this:

CategoryView(category: .entertainment)

It shows up fine:

Screenshot

Any ideas?


Solution

  • The answer to SwiftUI Picker issue with Rectangle() instead of Text() shows how this can be done (it was my answer):

    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)
                }
            }
        }
    }
    

    Screenshot