Programmatically determine order in which UIView items should be read by VoiceOver
Asked Answered
L

3

9

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"?

Librarianship answered 8/8, 2011 at 7:42 Comment(0)
S
6

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;
}
Sculley answered 25/3, 2013 at 11:39 Comment(0)
A
0

In some cases, setting UIAccessibilityTraitSummaryElement on one item can do this. (My game seems too dynamic for this to help much.)

Arce answered 5/10, 2011 at 23:32 Comment(1)
Or possibly not — I may misunderstand UIAccessibilityTraitSummaryElement, it may simply be what is spoken at screen entry. Which is not the same as the focused item.Arce
F
0

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))
    }
Felonious answered 18/1, 2023 at 17:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.