segmented picker removes accessibility

Viewed 164

I am trying to add accessibility to our swift code- for automation purposes The end goal is to tap on a button, that has a unique identifier.

current implementation looks like:

var body: some View {
   NavigationView {
      ZStack {
         VStack {
            HStack{
               Picker(selection: _ , label: Text("")) {
                  Image(systemName: "list.bullet").tag().accessibility(identifier: "list")
                  Image(systemName: "square.grid.3x2.fill").tag().accessibility(identifier: "grid")

               }
               .pickerStyle(SegmentedPickerStyle())
            }
         }
      }
   }
}

I believe when the .pickerStyle gets converted into segmented control, and the Images become Buttons, xcode removes all accessibility traits. The console output of app looks like:

 SegmentedControl, 0x60000121e4c0, {{668.0, 90.0}, {150.0, 32.0}}
        Button, 0x60000121e5a0, {{668.0, 90.0}, {74.0, 32.0}}, Selected
        Button, 0x60000121e680, {{743.0, 90.0}, {75.0, 32.0}}

In other areas, Image with .accessibility(identifier: "") works perfectly, so it has to have something to do with pickerStyle.

I've also tried this attributes for accessibility:

.accessibility(hidden: false)
.accessibility(label: "")
.accessibility(value: "")

Does anyone know how to work around this? So that in the end, the debugger could print:

 SegmentedControl, 0x60000121e4c0, {{668.0, 90.0}, {150.0, 32.0}}
        Button, 0x60000121e5a0, {{668.0, 90.0}, {74.0, 32.0}}, identifier: 'list', Selected
        Button, 0x60000121e680, {{743.0, 90.0}, {75.0, 32.0}}, identifier: 'grid'
1 Answers

Solution with Accessibility Labels

I had the same issue with accessibility labels for segmented pickers with images. Here's how I made it work (in a re-usable view):

enum Choice: CaseIterable, Hashable {
    case one, two, three
}

struct MyPickerView: View {
    @Binding var choice: Choice

    static let choices: [Choice: String] = [
        .one: "1.circle",
        .two: "2.circle",
        .three: "3.circle"
    ]

    static let hints: [Choice: LocalizedStringKey] = [
        .one: "One item",
        .two: "Two items",
        .three: "Three items"
    ]

    var body: some View {
        Picker(selection: $choice.animation(), label: Text("")) {
            ForEach(Choice.allCases, id: \.self) { choice in
                Image(systemName: Self.choices[choice]!)
                    .tag(choice)
                    // Needed for VoiceOver on unselected items
                    .accessibility(label: Text(Self.hints[choice]!))
            }
        }
        .pickerStyle(SegmentedPickerStyle())
        // Needed the first time VoiceOver is on the selected item
        .accessibility(label: Text(Self.hints[self.choice]!))
    }
}

Both .accessibility modifiers are needed in order for VoiceOver to speak the accessibility hint in all cases. It is then necessary to have an explicit @State or @Binding variable to keep a reference to the selection.

Related