Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIPageControl and VoiceOver/accessibility

When using voice over on the springboard, when the UIPageControl at the bottom of the screen is selected, VoiceOver announces something like "Page 1 of 5. Adjustable." and the user can swipe up and down to change pages.

In my app, I do not get the "Adjustable" part, and the pages cannot be changed by swiping.

Any ideas how I fix this? It obviously kills the usability of the app.

like image 574
Dan Wesnor Avatar asked Apr 01 '12 21:04

Dan Wesnor


2 Answers

I have subclassed UIPageControl and overrode the -accessibilityTraits getter to return UIAccessibilityTraitAdjustable getting Voice Over to read "adjustable".

To add actions: implement the -accessibilityIncrement and -accessibilityDecrement methods specified in the UIAccessibilityAction category.

Since my pages respond to the UIControlEventValueChanged events, I make sure to send actions for this event too.

Sample code

@interface AccessibleUIPageControl : UIPageControl

@end

@implementation AccessibleUIPageControl

- (UIAccessibilityTraits)accessibilityTraits
{
    return super.accessibilityTraits | UIAccessibilityTraitAdjustable;
}

- (void)accessibilityIncrement
{
    self.currentPage = self.currentPage + 1;
    [self sendActionsForControlEvents:UIControlEventValueChanged];
}

- (void)accessibilityDecrement
{
    self.currentPage = self.currentPage - 1;
    [self sendActionsForControlEvents:UIControlEventValueChanged];
}

@end
like image 137
micap Avatar answered Nov 20 '22 12:11

micap


If you're supporting iOS 9 and newer, this behavior is now the standard - no special handling required.

If you're supporting iOS 8 and lower, subclass UIPageControl and override accessibilityIncrement and accessibilityDecrement. You don't need to override the accessibilityTraits property to indicate it's adjustable - UIPageControl is adjustable by default.

import UIKit

class AccessibleUIPageControl: UIPageControl {

    override func accessibilityIncrement() {
        self.currentPage += 1
        self.sendActionsForControlEvents(.ValueChanged)
    }

    override func accessibilityDecrement() {
        self.currentPage -= 1
        self.sendActionsForControlEvents(.ValueChanged)
    }

}

Then in your view controller you can listen for ValueChanged and respond appropriately to show the content for the new page:

//viewDidLoad:
self.pageControl.addTarget(self, action: "didChangePage", forControlEvents: .ValueChanged)

func didChangePage() {
    let contentOffset: CGFloat = collectionView.frame.size.width * CGFloat(pageControl.currentPage)
    collectionView.setContentOffset(CGPointMake(contentOffset, 0), animated: false)
}

Note that if you don't subclass UIPageControl this target/action will still be called but the current page dot indicator will not update.

like image 5
Jordan H Avatar answered Nov 20 '22 12:11

Jordan H