Reputation: 1358
I have a class which subclasses UIAccessibilityElement for the purposes of enabling accessibility in my Cocos2D app.
At run time, the instances of this class are all navigable via iOS' accessibility features and this is great, but I have a specific need to be able to change the language and accent used by iOS (this will only work on iOS7+) for each element.
I note that to do this I am supposed to override the:
- (NSString*) accessibilityElementLanguage;
message, which I have done.
I've confirmed via the accessibility inspector in the simulator that the correct language ID is being returned (it is displayed in the inspector).
When voiceover reads the text associated with the element however, it insists on using the default device voice and language, so Spanish words are understandably sounding completely incorrect.
I'm not sure what I'm doing wrong. When the language setting failed to work, I tried a workaround whereby I would handle a accessibilityElementDidBecomeFocused callback and read the text using my own code, but now I don't even get the callbacks for the focus events unless I am running the simulator with the accessibility inspector enabled, and I touch one of my elements.
I'm sure I have something simple wrong here. Any help would be appreciated.
The code for the class interface is:
#import <UIKit/UIKit.h>
#import "CCSwitchableNode.h"
#import <UIKit/UIAccessibility.h>
@interface AccessibleSwitchableNode : UIAccessibilityElement <UIAccessibilityIdentification>
- (id) initWithNode:(id<CCSwitchableNode>)node inContainer:(id)container;
+ (AccessibleSwitchableNode*) accessibleSwitchableWithNode:(id<CCSwitchableNode>)node inContainer:(id)container;
@property (nonatomic, retain) id<CCSwitchableNode> node;
@end
And the implementation:
#import "AccessibleSwitchableNode.h"
#import <UIKit/UIAccessibility.h>
#import <UIKit/UIAccessibilityElement.h>
@implementation AccessibleSwitchableNode {
BOOL isFocused_Local;
}
- (id) initWithNode:(id<CCSwitchableNode>)node inContainer:(id)container {
self = [super initWithAccessibilityContainer:container];
if (self != nil) {
isFocused_Local = NO;
self.node = node;
// This code is a quick hack to translate the position from Cocos2d in one specific orientation
// to UIKit. To be finessed.
//
CGPoint uiPoint = [[CCDirector sharedDirector] convertToUI:[node switchableNodePosition]];
uiPoint.x = [CocosUtil screenWidth] - uiPoint.x;
self.accessibilityFrame =
CGRectMake(uiPoint.y-([node switchableNodeSize].height/2.0f),
uiPoint.x-([node switchableNodeSize].width/2.0f),
[node switchableNodeSize].height,
[node switchableNodeSize].width);
self.accessibilityLabel = [node textForSpeaking];
self.accessibilityValue = [node textForSpeaking];
self.accessibilityTraits = UIAccessibilityTraitButton;
self.accessibilityActivationPoint = CGPointMake(uiPoint.y, uiPoint.x);
}
return self;
}
+ (AccessibleSwitchableNode*) accessibleSwitchableWithNode:(id<CCSwitchableNode>)node inContainer:(id)container {
return [[[AccessibleSwitchableNode alloc] initWithNode:node inContainer:container] autorelease];
}
- (void) dealloc {
self.node = nil;
[super dealloc];
}
// Called when the object is first added, but has no effect on pronunciation.
//
- (NSString*) accessibilityLanguage {
return [self.node languageForText];
}
// Never called unless on the simulator with the inspector active.
//
- (void) accessibilityElementDidBecomeFocused {
NSLog(@"accessibilityElementDidBecomeFocusedd: %@", self.accessibilityLabel);
isFocused_Local = YES;
}
// Never called unless on the simulator with the inspector active.
//
- (void) accessibilityElementDidLoseFocus {
NSLog(@"accessibilityElementDidLoseFocus: %@", self.accessibilityLabel);
isFocused_Local = NO;
}
// Never called unless on the simulator with the inspector active.
//
- (BOOL) accessibilityElementIsFocused {
NSLog(@"accessibilityElementIsFocused: %@", self.accessibilityLabel);
return isFocused_Local;
}
// Never called unless on the simulator with the inspector active.
//
- (BOOL) accessibilityActivate {
if ([self.node isSwitchSelectable] == YES) {
[self.node switchSelect];
return YES;
} else {
return NO;
}
}
- (BOOL) isAccessibilityElement {
return [self.node isSwitchSelectable];
}
@end
The protocol for the Cocos2D nodes that I am adding to the AccessibilityElements is:
#import <Foundation/Foundation.h>
@protocol CCSwitchableNode <NSObject>
// Should return the size of the node on screen.
//
- (CGSize) switchableNodeSize;
// Should return the position (center) of the node in screen coordinates.
//
- (CGPoint) switchableNodePosition;
// Should return YES if the node is currently able to accept taps by the user.
//
- (BOOL) isSwitchSelectable;
// Should cause the node, be it a button of some sort, or something else, to act as if it has been
// tapped. This will be called when a switch is used to "select" an item on the screen.
//
- (void) switchSelect;
// Should return YES if the node would prefer to highlight itself to the user as selectable. If this
// happens, the SwitchControlLayer will call the setSwitchHighlighted: as appropriate in
// order to turn on or off the highlight.
//
- (BOOL) hasOwnHighlight;
// Should return a NSString containing the text to be spoken when the node is highlighted. If no text is
// to be spoken, then nil should be returned.
//
- (NSString*) textForSpeaking;
// Should return a NSString containing the language locale to use when speaking the nodes text.
//
- (NSString*) languageForText;
@optional
// This optional method should be implemented in classes that can return YES from the hasOwnHighlight
// method. The SwitchControlLayer will call this instead of using it's own built-in highlight
// to turn on, or off the highlight.
//
- (void) setSwitchHighlighted:(BOOL)highlighted;
@end
Upvotes: 0
Views: 1805
Reputation: 1358
As per some of my comments above, the short answer is that iOS7 does not support the various callbacks and API's for Switch Control in the same way that VoiceOver does. What works for VoiceOver will not necessarily work for Switch Control.
Having filed a bug with Apple, and interacted with them there, testing my code against iOS8 shows that support for Switch Control has improved by beta 5, but is still incomplete. The accessibilityElementDidBecomeFocused callbacks appear to work now however Switch Control still refuses to use the accessibilityElementLanguage callback.
Upvotes: 1
Reputation: 20609
This may surprise and frighten you, but even Apple ships bugs. If you're encountering unexpected or subjectively "wrong" behavior, consider filing a Radar with comprehensive reproduction steps and a sample project.
Upvotes: 1