简体   繁体   中英

BottomBar BarButtonItem Voice Over accessibility is broken

I've noticed that there are some issues with standard Voice Over behaviour with BarButtonItems when they are placed in the bottom bar of a View.

In a test app I've made the following simple view

测试应用程序显示顶部栏,底部栏按钮项和标签

With the following code I'm updating all 3 text elements so they count up every second.

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UILabel *testLabel;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *testBarButtonItem;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *testBottomBarItem;

@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic) NSInteger count;

@end

@implementation ViewController

- (void)viewDidLoad
{
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

  self.count = 0;
  self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];

  // run the timer for the common modes so it's not interrupted with scrolling - should be ticked in pretty much all modes now
  [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

  self.testLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
  self.testBarButtonItem.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
  self.testBottomBarItem.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
}

-(void)updateTimer:(NSTimer*)theTimer
{
  self.testLabel.text = [NSString stringWithFormat:@"Label with value %d", (int)self.count];
  self.testBarButtonItem.title = [NSString stringWithFormat:@"Top Item with title %d", (int)self.count];
  self.testBottomBarItem.title = [NSString stringWithFormat:@"Bottom Item with title %d", (int)self.count];
  self.count++;
}

Testing this app on my iPhone 6+ with Voice Over enabled, the following occurs

  • The Top Bar Button Item pulses as it updates its content
  • The Top Bar Button Item reads out its updated content correctly due to the UIAccessibilityTraitUpdatesFrequently trait being set
  • The Label in the centre reads out its updated content correctly due to the UIAccessibilityTraitUpdatesFrequently trait being set
  • The Bottom Bar Button Item does NOT read out its updated content correctly, even though it too has the UIAccessibilityTraitUpdatesFrequently trait set
  • when navigating Accessibility elements with left/right swipes starting from the top bar button item, selection correctly moves down to the label with a right swipe, but from there a right swipe takes the selection to the top left of the view (where no control resides). It then reads out the initial bottom bar button content "Bottom Item With title 0" regardless of what the bottom button actually reads. Only when actively selecting the bottom bar item does it actually correctly select it and read it out. But as already described it does not go on to continue reading it out

The navigation bug I believe is maybe new in iOS 8.4 as I've not noticed it in my main app that I've been doing voice over testing for a long time, but I could have just missed it.

I've not had much success with using UIAccessibilityTraitUpdatesFrequently in my own app, yet I see other apps out there that seemingly are working with it correctly. So if anyone can point out something that I'm doing wrong that'd be great. Otherwise I think I'll log a radar bug about this.

For reference I've now put up the entire project as a zip for download here

There's a video of this bug in action here

https://youtu.be/QokQ0MDGyZM

You seem to misunderstand what the UIAccessibilityTraitUpdatesFrequently does. It is not there to ensure your content is read out as it changes dynamically. It is there to ensure that overly verbose content, like a timer, does not read out every update. For example, if you were to put focus onto a timer that updated every second. VoiceOver would read out

1 2 3 4 ...

However, let's say that this is a time. So it has to read out:

1 hour, 20 minutes, 55 seconds 1 hour, 20 minutes, 56 seconds ...

BUT, by the time it has read the entire first announcement "... 55 seconds" the timer now actually reads 1:21:00. Yet it still reads out "... 56 seconds" and would then continue to read out "... 57 seconds" meanwhile, the timer and the actual announcement are getting farther and farther out of sync.

There is nothing that will automatically read out auto updating content, if VoiceOver is not focusing it. This would cause havoc, and a lot of accessibility issues. It is on the developer to notify VoiceOver of dynamic changes by appropriately posting the following three accessibility notifications:

UIAccessibilityLayoutChangedNotification
UIAccessibilityScreenChangedNotification
UIAccessibilityAnnouncementNotification

Note that the behavior of these is a little unstable in your typical testing environment. In particular I've found that, you want to ensure that you have VoiceOver on BEFORE you open your app. Using the quick toggle shortcut while your app is up is a good way to bug VoiceOver out when it comes to the notification system. Even better is to turn VoiceOver on, restart your phone, and leave it on while you test.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM