6

I'm having a great deal of trouble with iOS 7/8 UIAccessibility. The specific use case I am working with is what I would expect to be a pretty common "progress saved" use case.

EDIT: It has been brought to my attention that the desired outcome was not clear from my original question, so I've added a description here: The goal is for the "progress saved" message to be spoken via VoiceOver, either in lieu of the NavigationBar title being spoken, or after it has been spoken. I'm not sure what the typical behaviour is for accessibility in this case, so maybe someone familiar with iOS Accessibility can clarify this as well.

Starting from the simplest solution, and working towards the most complicated, I tried the following approaches.

-(void) showProgressSavedPanel {

    ... // present the panel toast
    NSString * message = NSLocalizedString(@"Your progress has been saved.", @"Progress saved message");
    UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, message);
}

Unfortunately, with this approach, the announcement is quickly interrupted by VoiceOver when it automatically speaks the navbar title followed by the title of the back button. The actual VoiceOver result is something like "Your progress has -- Navbar Title -- Back Button."

Reading on about iOS accessibility, I discovered a new API, which also does not seem to work. Having added a new IBOutlet pointing directly to the progress saved label, I replaced the code above with the following:

-(void) showProgressSavedPanel {

    ... // present the panel toast
    UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, _progressSavedLabel);
}

Using either UIAccessibilityScreenChangedNotification or UIAccessibilityLayoutChangedNotification had the same outcome: the expected message was not spoken whatsoever. No matter what I do it seems like VoiceOver just wants to speak the navbar title.

I have come up with a solution that makes me a very sad panda, which is to use the first solution except post the announcement notification after an arbitrary delay (1.5 seems to work), causing the announcement to occur after the back bar button item has been spoken.

Does anyone know of a better approach?

Thanks in advance :)

Justin
  • 20,509
  • 6
  • 47
  • 58
dave
  • 1,150
  • 1
  • 13
  • 22
  • 1
    What are you trying to do? Select an item when a view appears or read out the progress as you get callbacks? – David Rönnqvist Nov 10 '14 at 16:02
  • Have VoiceOver announce the content of a "progress saved" toast that appears on viewDidAppear. From `UIAccessibilityConstants.h`, `UIAccessibilityLayoutChangedNotification` should be posted when the layout of a screen changes, for example when an individual element appears or disappears (optionally with an element parameterized). However, only the announcement approach successfully speaks the content of the element. – dave Nov 10 '14 at 16:13
  • @DavidRönnqvist thanks for your feedback; I've updated the question above to clarify the expected outcome. – dave Nov 10 '14 at 16:22

2 Answers2

5

You may not be able to achieve the desired effect with either API out-of-the-box. As you observed, the timing is a bit tricky, likely due to efforts VoiceOver, itself, is making to begin reading screen content after loading completes.

In my opinion, transient visible notifications like toast dialogs are best described using an announcement. You also want the announcement to voice after the user is told which screen they're on. While not ideal, you're right to consider posting the announcement after an artificial, hardcoded delay. Once implemented, experiment with different localizations to ensure it's consistently read after the title.

Justin
  • 20,509
  • 6
  • 47
  • 58
  • It's looking more and more like this is the answer. I guess this highlights another problem with our spec, which is that the toast disappears after ~3 seconds, slightly before the dialog is completely announced. I've started moving towards an approach in which I'm consistently delaying VoiceOver announcements by arbitrary delays appropriate for each view controller. As long as this doesn't surprise the accessibility-enabled user, I think all should be well. :) – dave Nov 10 '14 at 19:13
  • Good discussion here. Marked as accepted answer for now. Maybe the UIAccessibility landscape and API will change with time. In my opinion `UIAccessibilityLayoutChangedNotification` would ideally work as advertised (at least as far as my interpretation is concerned) in Apple's documentation. – dave Nov 10 '14 at 19:15
  • The docs for `UIAccessibilityLagoutChangedNotification` don't rule out this use case, but the comment on `UIAccessibilityAnnouncementNotification` explicitly identifies it: `"Use this notification to provide accessibility information about events that do not update the application user interface (UI), or that update the UI only briefly."` – Justin Nov 10 '14 at 22:10
2

Let the VoiceOver do it's primary task then post the Notification to announce the desired instruction with the help of "dispatch_after" execution block.

// Delay execution of my block for 2 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @"desiredInstructionString"); });
slfan
  • 8,950
  • 115
  • 65
  • 78