Обратные вызовы UIAccessibilityElement не вызывались

У меня есть класс, который подклассов UIAccessibilityElement для целей обеспечения доступности в моем приложении Cocos2D.

Во время выполнения все экземпляры этого класса доступны для навигации с помощью специальных возможностей iOS, и это замечательно, но у меня есть особая необходимость иметь возможность менять язык и акцент, используемые iOS (это будет работать только на iOS7+) для каждого элемент.

Я отмечаю, что для этого я должен переопределить:

- (NSString*) accessibilityElementLanguage;

сообщение, которое я сделал.

С помощью инспектора специальных возможностей в симуляторе я подтвердил, что возвращается правильный идентификатор языка (он отображается в инспекторе).

Однако когда голос за кадром читает текст, связанный с элементом, он настаивает на использовании голоса и языка устройства по умолчанию, поэтому испанские слова звучат совершенно неверно.

Я не уверен, что я делаю неправильно. Когда языковая настройка не работала, я попробовал обходной путь, посредством которого я обработал бы обратный вызов accessibilityElementDidBecomeFocused и прочитал текст, используя свой собственный код, но теперь я даже не получаю обратные вызовы для событий фокуса, если я не запускаю симулятор с инспектор доступности включен, и я касаюсь одного из своих элементов.

Я уверен, что у меня тут что-то не так. Любая помощь будет оценена.

Код для интерфейса класса:

#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

И реализация:

#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

Протокол для узлов Cocos2D, который я добавляю в AccessibilityElements:

#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

2 ответа

Как указано в некоторых моих комментариях выше, короткий ответ заключается в том, что iOS7 не поддерживает различные функции обратного вызова и API для управления коммутацией так же, как VoiceOver. То, что работает для VoiceOver, не обязательно будет работать для Switch Control.

Отправив сообщение об ошибке в Apple и поработав с ними там, тестирование моего кода на iOS8 показывает, что поддержка Switch Control улучшилась к бета-версии 5, но все еще не завершена. Обратные вызовы accessibilityElementDidBecomeFocused теперь работают, однако Switch Control по-прежнему отказывается использовать обратный вызов accessibilityElementLanguage.

Это может вас удивить и напугать, но даже Apple доставляет ошибки. Если вы столкнулись с неожиданным или субъективно "неправильным" поведением, рассмотрите возможность регистрации радара с подробными шагами воспроизведения и примером проекта.

Другие вопросы по тегам