有时您需要在自定义视图中从 CoreAnimation 层构建用户界面。不幸的是,它们不受 NSAccessibility 支持,从而使 UI 对您的残疾用户无用。
所以,我开发了一个解决方案,它通过类别向 CALayer 及其所有子类添加 NSAccessibility 支持,并提供了一个易于使用的基于块的 API
-(void)setReadableAccessibilityAttribute:(NSString*)attribute withBlock:(id(^)(void))handler;
CATextLayer *layer...
__weak CATextLayer *weakLayer = layer;
[layer setReadableAccessibilityAttribute:NSAccessibilityTitleAttribute
withBlock:^id{
CATextLayer *strongLayer = weakLayer;
return strongLayer.string;
}];
使用此方法,您可以将一个可访问性属性设置到一个 CALayer,处理程序块必须返回与属性(如 NSString、NSValue、NSArray 等)特定的值(请参阅 Apple 开发者网站上关于 NSAccessibility 文档的 NSAccessibility Documentation)。
-(void)setWritableAccessibilityAttribute:(NSString*)attribute readBlock:(id(^)(void))getter writeBlock:(void(^)(id value))setter;
CATextLayer *layer = ...*
[layer setWritableAccessibilityAttribute:NSAccessibilityTitleAttribute readBlock:^id{
return weakLayer.string;
} writeBlock:^(NSString *value) {
weakLayer.string = value;
}];
此方法将为 CALayer 提供一个可设置的属性。因为每个可设置的属性都需要可读性,您必须提供getter块。
-(void)setParameterizedAccessibilityAttribute:(NSString*)parameterizedAttribute withBlock:(id(^)(id))handler;
[layer setParameterizedAccessibilityAttribute:NSAccessibilityLineForIndexParameterizedAttribute
withBlock:^id(id param) {
return @0;
}];
在这里,您提供了一个块,当系统 ax-service 请求层参数化可访问性值(如文本字段中的当前光标位置)时将调用此块。
-(void)setAccessibilityAction:(NSString*)actionName withBlock:(void(^)(void))handler
[layer setAccessibilityAction:NSAccessibilityPressAction
withBlock:^{
NSLog(@"action pressed");
}];
由于处理程序块存储在各个层上,因此当您在这些块中回引用层时,需要小心以避免保留周期。请在块内部始终使用弱self引用,并在块中将它转换回强引用。
有关如何使用库的详细示例,请查看 LayerView 类。
由于库实现了大量的默认 NSAccessibility 属性,您只需提供与您的 UI 相关的特定属性。内置属性如下
NSAccessibilityRoleAttribute
NSAccessibilityParentAttribute
NSAccessibilitySizeAttribute
NSAccessibilityPositionAttribute
NSAccessibilityWindowAttribute
NSAccessibilityTopLevelUIElementAttribute
NSAccessibilityRoleDescriptionAttribute
NSAccessibilityEnabledAttribute
NSAccessibilityFocusedAttribute
NSAccessibilityRoleAttribute 的默认值是 NSAccessibilityUnknownRole,因此您应该提供一个自己的处理程序,返回更具体的角色,例如 NSAccessibilityButtonRole 或 NSAccessibilityTextFieldRole。有关详细信息,请参阅示例项目。
默认情况下,每个没有至少一个用户定义处理程序的层都会被忽略。要为层的大小、位置、父级等提供默认处理程序,当您设置视图的层时,需要在您的自定义 NSView 中调用一个额外的方法
CALayer *layer = [self createBackgroundLayer];
[self setAccessiblityEnabledLayer:layer];
然后您只需在您的自定义视图中实现 NSAccessibility 协议的两个占位方法
-(NSArray*)accessibilityAttributeNames
{
static NSMutableArray *attributes = nil;
if (!attributes) {
attributes = [[super accessibilityAttributeNames] mutableCopy];
NSArray *appendedAttributes = @[NSAccessibilityChildrenAttribute];
for (NSString *attribute in appendedAttributes) {
if (![attributes containsObject:attributes]) {
[attributes addObject:attribute];
}
}
}
return attributes;
}
-(id)accessibilityAttributeValue:(NSString *)attribute
{
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
return NSAccessibilityUnignoredChildren(@[self.layer]);
}
return [super accessibilityAttributeValue:attribute];
}
请参阅提供的示例中的 LayerView 类。
该库使用 Kiwi 规范进行了全面单元测试。
要运行示例项目;克隆仓库,然后首先从示例目录运行 pod install
。
然后请确保系统设置中启用了辅助功能,然后启动辅助功能检查器。
您可以在检查器中检查基于CALayer的用户界面。
最低要求是Mac OSX 10.7和ARC。
MMLayerAccessibility在MIT许可证下可用。有关更多信息,请参阅LICENSE文件。