How do I set the accessibility label for a particu

2019-01-25 04:59发布

问题:

We use KIF for our functional testing, and it uses the accessibility label of elements to determine where to send events. I'm currently trying to test the behaviour of a UISegmentedControl, but in order to do so I need to set different accessibility labels for the different segments of the control. How do I set the accessibility label for a particular segment?

回答1:

I'm just getting started with KIF myself, so I haven't tested this, but it may be worth a try. I'm sure I'll have the same issue soon, so I'd be interested to hear if it works.

First, UIAccessibility Protocol Reference has a note under accessibilityLabel that says:

"If you supply UIImage objects to display in a UISegmentedControl, you can set this property on each image to ensure that the segments are properly accessible."

So, I'm wondering if you could set the accessibilityLabel on each NSString object as well and be able to use that to access each segment with KIF. As a start, you could try creating a couple of strings, setting their accessibility labels, and using [[UISegmentedControl alloc] initWithItems:myStringArray]; to populate it.

Please update us on your progress. I'd like to hear how this goes



回答2:

As Vertex said,

obj-c

[[[self.segmentOutlet subviews] objectAtIndex:3] setAccessibilityLabel:@"GENERAL_SEGMENT"];

swift

self.segmentOutlet.subviews[3].accessibilityLabel = "GENERAL_SEGMENT"

some advice so you don't go crazy like I did:

  1. To scroll in accessibility mode swipe three fingers
  2. The indexes of the segments are backwards than you would expect, i.e. the furthest segment to the right is the 0th index and the furthest to the left is the n'th index where n is the number of elements in the UISegmentControl


回答3:

Each segment of UISegmentedControl is UISegment class instance which subclass from UIImageView. You can access those instances by subviews property of UISegmentedControl and try to add accessibility for them programmatically.



回答4:

This is an old question but just in case anyone else runs up against this I found that the segments automatically had an accessibility label specified as their text. So if two options were added of Option 1 and Option 2. A call to

[tester tapViewWithAccessibilityLabel:@"Option 2"];

successfully selected the segment.



回答5:

This is an old question but just in case anyone else runs up against this I found that the segments automatically had an accessibility label specified as their text.

Further to Stuart's answer, I found it really useful when writing test cases to turn on 'Accessibility Inspector' on the Simulator (Settings -> General -> Accessibility -> Accessibility Inspector). You'd be surprised how many elements already have accessibility labels included, like in the standard iOS UI elements or even third party frameworks.

Note: Gestures will now be different - Tap to view accessibility information, double tap to select. Minimizing the Accessibility Inspector window (by tapping the X button) will return the gestures back to normal.



回答6:

You can't rely on the index in the subviewsarray for the position. For customisation of the individual subviews I sort the subviews on their X Position before setting any propery.What would also be valid for accesibilityLbel.

let sortedViews = self.subviews.sorted( by: { $0.frame.origin.x < $1.frame.origin.x } )

sortedViews[0].accessibilityLabel = "segment_full"
sortedViews[1].accessibilityLabel = "segment_not_full"


回答7:

another option if not willing to set accesibility label might be calculating the poistion of each segment part and use

[tester tapScreenAtPoint:segementPosition];

to trigger the actions



回答8:

If you look at the segmented control thru the accessibility inspector, you find that the segments are UISegment objects. Moreover, they turn out to be direct subviews of the UISegmentedControl. That fact suggests the following insanely crazy but perfectly safe Swift 4 code to set the accessibility labels of the segments of a UISegmentedControl:

    let seg = // the UISegmentedControl
    if let segclass = NSClassFromString("UISegment") {
        let segments = seg.subviews.filter {type(of:$0) == segclass}
            .sorted {$0.frame.minX < $1.frame.minX}
        let labels = ["Previous article", "Next article"] // or whatever
        for pair in zip(segments,labels) {
            pair.0.accessibilityLabel = pair.1
        }
    }


回答9:

You guys want to see how Apple recommends it be done?

It's FUGLY.

This is from this example:

func configureCustomSegmentsSegmentedControl() {
    let imageToAccessibilityLabelMappings = [
        "checkmark_icon": NSLocalizedString("Done", comment: ""),
        "search_icon": NSLocalizedString("Search", comment: ""),
        "tools_icon": NSLocalizedString("Settings", comment: "")
    ]

    // Guarantee that the segments show up in the same order.
    var sortedSegmentImageNames = Array(imageToAccessibilityLabelMappings.keys)
    sortedSegmentImageNames.sort { lhs, rhs in
        return lhs.localizedStandardCompare(rhs) == ComparisonResult.orderedAscending
    }

    for (idx, segmentImageName) in sortedSegmentImageNames.enumerated() {
        let image = UIImage(named: segmentImageName)!

        image.accessibilityLabel = imageToAccessibilityLabelMappings[segmentImageName]

        customSegmentsSegmentedControl.setImage(image, forSegmentAt: idx)
    }

    customSegmentsSegmentedControl.selectedSegmentIndex = 0

    customSegmentsSegmentedControl.addTarget(self,
                                             action: #selector(SegmentedControlViewController.selectedSegmentDidChange(_:)),
                                             for: .valueChanged)
}

They apply the accessibility labels to images, and then attach the images. Not too different from the above answer.



回答10:

As Vortex said, the array is right to left with [0] starting on the right. You can set every single accessibility option by accessing the subviews. Since the subviews are optional, it is good to pull out the subview first, and then assign the accessibility traits that you want. Swift 4 example for a simple two option segment control:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    guard let rightSegment = segmentControl.subviews.first, let leftSegment = segmentControl.subviews.last else { return }
    rightSegment.accessibilityLabel = "A label for the right segment."
    rightSegment.accessibilityHint = "A hint for the right segment."
    leftSegment.accessibilityLabel = "A label for the left segment."
    leftSegment.accessibilityHint = "A hint for the left segment."
}