I am making my iPhone app accessible. VoiceOver is pretty impressive. When a user uses VoiceOver, it automatically reads off the items on the screen and allows the user to double-tap anywhere on the screen to select that item. However, I want VoiceOver to read the items in a specific order, but it always begins with the UINavigationBar items including the back button. I don't want these items not to be read at all, I just want to start with a specific item. Is there a VoiceOver-equivalent of "firstResponder"?
Yes
There is a protocol called UIAccessibilityContainer
that is implemented by NSObject. It enables you to customize the container behaviour using these three methods:
accessibilityElementCount
accessibilityElementAtIndex:
indexOfAccessibilityElement:
If you have a main view where you want to control the order of the accessibility elements you would just implement these three methods and return the suitable view/index. One more thing is that the container view cannot be an accessibility element itself so you should override isAccessibilityElement:
and return NO
;
- (BOOL)isAccessibilityElement {
return NO;
}
Example implementations
I suggest that you either have an array of all the views in the order you want them to appear or use the tag
property if you don't use it for anything else. The implementation of the protocol becomes super simple.
Array of elements
I'm assuming that you have an array called accessibleElements
that store the elements in the correct order.
- (NSInteger)accessibilityElementCount {
return self.accessibleElements.count;
}
- (id)accessibilityElementAtIndex:(NSInteger)index {
return self.accessibleElements[index];
}
- (NSInteger)indexOfAccessibilityElement:(id)element {
return [self.accessibleElements indexOfObject:element];
}
Tagged elements
I'm assuming that your subviews are tagged continuously from 0 up to the number of subviews.
- (NSInteger)accessibilityElementCount {
return self.subviews.count;
}
- (id)accessibilityElementAtIndex:(NSInteger)index {
// Not that self should have a tag<0 or tag>count otherwise it will
// return itself for that tag instead of the element you want it to.
return [self viewWithTag:index];
}
- (NSInteger)indexOfAccessibilityElement:(id)element {
return ((UIView *)element).tag;
}
In some cases, setting UIAccessibilityTraitSummaryElement on one item can do this. (My game seems too dynamic for this to help much.)
Swift 5 You can specify the order of element in accessibilityElements property
self.accessibilityElements = [lable1, label2, label2].compactMap {$0}
For specifying the order of CollectionView cells.
// MARK: collection view accessibility order
override func accessibilityElementCount() -> Int {
return numberOfItemInSection()// specify your items count
}
override func accessibilityElement(at index: Int) -> Any? {
return collectionView.cellForItem(at: IndexPath(item: index, section: 0))
}
© 2022 - 2024 — McMap. All rights reserved.