Search code examples
arraysswiftmacosswiftui-foreachswiftui-picker

Coloured options in a drop down Picker using ForEach in Swift UI


I'm interested in creating menu similar to one displayed in the screenshot below. Sample

This menu is accessible via Rules settings of Mail.app. I'm interested in colouring the symbol on the left hand side. I don't care about the Other... button and functionality.

Example

ContentView.swift

import SwiftUI

struct ContentView: View {

    let availableColours: [String] = ["yellow", "green", "red", "blue"]
    @Binding var selectedOption: Int

    var body: some View {
        VStack {
            Picker("Colour:", selection: $selectedOption) {
                ForEach(0..<availableColours.count) { index in
                    HStack {
                        Image(systemName: "rectangle.fill")
                            .symbolRenderingMode(.monochrome)
                            .foregroundColor(.red)
                        Text(availableColours[index]).tag(availableColours[index])
                    }
                }
            }
            .pickerStyle(.menu)
            .padding()
        }
        .frame(maxWidth: 200)
    }
}

struct BindingViewExamplePreviewContainer: View {
    @State private var defaultChoice = 1

    var body: some View {
        ContentView(selectedOption: $defaultChoice)
    }
}

#Preview {
    BindingViewExamplePreviewContainer()
}

App.swift

import SwiftUI

@main
struct ExperimentsDropDownApp: App {
    @State private var defaultChoice = 1
    var body: some Scene {
        WindowGroup {
            ContentView(selectedOption: $defaultChoice)
        }
    }
}

+Color.swift

import SwiftUI
extension Color {

    init?(wordName: String) {
        switch wordName {
        case "clear":       self = .clear
        case "black":       self = .black
        case "white":       self = .white
        case "gray":        self = .gray
        case "red":         self = .red
        case "green":       self = .green
        case "blue":        self = .blue
        case "orange":      self = .orange
        case "yellow":      self = .yellow
        case "pink":        self = .pink
        case "purple":      self = .purple
        case "primary":     self = .primary
        case "secondary":   self = .secondary
        default:            return nil
        }
    }
}

Problem

The symbol is not coloured.

resulting menu


Solution

  • SF Symbols can be displayed colored with the .palette rendering mode.