Aaron
Aaron

Reputation: 6714

How to select a Picker with MenuPickerStyle outside of the label text

I have a simple menu picker that I have placed within a rounded rectangle border and chevron image. I'd like for users to be able to tap anywhere within this rectangle to activate the showing of the picker options but no matter what it only seems to be selectable within the actual text (see image with highlighted blue border). Is there any way to achieve this without scaling the text?

I've tried adding padding and scaling modifiers with no such luck.

var body: some View {
    ZStack {
        HStack {
            Rectangle()
                .foregroundColor(Color.black)
                .frame(height: 40)
            Image(uiImage: Icon.chevronDown.image())
                .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 8))
        }
        .overlay(
            RoundedRectangle(cornerRadius: 5)
                .stroke(Color.black, lineWidth: 1)
        )
        .padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
        Picker(selectedOption, selection: $selectedOption) {
            ForEach(options, id: \.self) { option in
                Text(option)
            }
        }
        .pickerStyle(MenuPickerStyle())
    }
}

picker menu

How can I make the white area between the rounded black border and the blue text selectable to active the menu picker options the same way as tapping on the actual blue text?

Upvotes: 4

Views: 2262

Answers (1)

Adam
Adam

Reputation: 5145

Use Picker(selection:label:content:), which takes a View as the label: argument. Put everything you want as the tappable view inside the label: argument, like so:

var body: some View {
        
    Picker(selection: $selectedOption, label:
            
            HStack {
                Rectangle()
                    .foregroundColor(Color(.systemBackground))
                    .frame(height: 40)
                Image(systemName: "chevron.down")
                    .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 8))
            }
            .overlay(
                RoundedRectangle(cornerRadius: 5)
                    .stroke(Color.black, lineWidth: 1)
            )
            .overlay(
                Text("Picker Option \(selectedOption)")
            )
            .padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
    ) {
        ForEach(options, id: \.self) { option in
            Text("Picker Option \(option)")
        }
    }
    .pickerStyle(MenuPickerStyle())
}

Update: The above code doesn’t work in Xcode 13 beta 5. Hopefully it’s a bug, but if not, here is a workaround: put the Picker in a Menu!

var body: some View {
        
    Menu {
        Picker("picker", selection: $selectedOption) {
            ForEach(options, id: \.self) { option in
                Text("Picker Option \(option)")
            }
        }
        .labelsHidden()
        .pickerStyle(InlinePickerStyle())

    } label: {

        HStack {
            Rectangle()
                .foregroundColor(Color(.systemBackground))
                .frame(height: 40)
            Image(systemName: "chevron.down")
                .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 8))
        }
        .overlay(
            RoundedRectangle(cornerRadius: 5)
                .stroke(Color.black, lineWidth: 1)
        )
        .overlay(
            Text("Picker Option \(selectedOption)")
        )
        .padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
    }
}

Upvotes: 6

Related Questions