Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 648
Jason Avatar asked Aug 08 '11 07:08

Jason


People also ask

What is isaccessibilityelement?

A Boolean value that indicates whether the element is an accessibility element that an assistive app can access.

How to group accessibility elements?

To successfully group accessibility elements, the key is to wrap them all in some sort of a “container” view, and then set an array of child elements on that container view's accessibilityElements property.

Should groups be accessibility?

A Boolean value that indicates whether VoiceOver groups the accessibility elements that are children of the element, regardless of their positions on the screen.


1 Answers

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;
}
like image 188
David Rönnqvist Avatar answered Sep 25 '22 04:09

David Rönnqvist