Objective-C中的UIAccessibility无障碍功能开发
2022-01-121.8k 阅读
一、UIAccessibility 简介
在当今数字化的时代,确保所有用户,包括残障人士,都能平等地使用应用程序至关重要。UIAccessibility 是 iOS 系统中提供的一套强大的无障碍功能框架,它允许开发者使应用程序对残障用户更友好,例如视力障碍者可通过 VoiceOver 屏幕阅读器来理解应用界面,肢体残疾者可以使用辅助输入设备来与应用进行交互。
Objective - C 作为 iOS 开发的传统语言,对 UIAccessibility 的支持非常全面。通过遵循 UIAccessibility 协议和使用相关类与方法,开发者能够将无障碍功能无缝集成到应用中。
二、UIAccessibility 基础概念
- 无障碍元素
- 应用中的每个可交互的视图或控件,如按钮、文本框、标签等,都可以成为一个无障碍元素。这些元素需要向无障碍服务提供足够的信息,例如元素的名称、用途、当前状态等,以便残障用户能够理解并与之交互。
- 在 Objective - C 中,UIView 及其子类默认支持 UIAccessibility。开发者可以通过设置相关属性来配置无障碍信息。
- 无障碍层次结构
- iOS 系统将应用中的所有无障碍元素组织成一个层次结构。这个层次结构与视图层次结构密切相关,但并不完全相同。无障碍层次结构的遍历顺序决定了 VoiceOver 等无障碍服务按什么顺序向用户介绍界面元素。
- 开发者需要确保无障碍层次结构的合理性,避免出现混乱的导航顺序,从而给残障用户带来困扰。
- 无障碍特征
- 无障碍特征用于描述元素的行为和状态,例如按钮是否可点击、开关是否打开、文本字段是否可编辑等。通过设置这些特征,开发者可以让无障碍服务准确地向用户传达元素的当前情况。
三、配置无障碍元素
- 设置无障碍标识符(Accessibility Identifier)
- 无障碍标识符是一个字符串,用于唯一标识应用中的一个无障碍元素。这在自动化测试和屏幕阅读器导航中非常有用。
- 在 Objective - C 中,为视图设置无障碍标识符非常简单,例如:
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeSystem];
myButton.accessibilityIdentifier = @"my_special_button";
- 设置无障碍标签(Accessibility Label)
- 无障碍标签是对元素的简短描述,用于告知用户该元素的用途。对于按钮,标签通常就是按钮上显示的文字,但对于一些非文本类的元素,如图标按钮,需要明确设置标签。
- 示例代码如下:
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"settings_icon"]];
iconView.accessibilityLabel = @"设置图标";
- 设置无障碍提示(AccessibilityHint)
- 无障碍提示是对用户操作元素后预期结果的简短描述。例如,对于一个删除按钮,可以设置提示为“点击删除当前项目”。
- 代码示例:
UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeSystem];
[deleteButton setTitle:@"删除" forState:UIControlStateNormal];
deleteButton.accessibilityHint = @"点击删除当前项目";
- 设置无障碍值(Accessibility Value)
- 对于一些有取值的元素,如滑块、进度条等,无障碍值用于向用户传达当前的取值。
- 以 UISlider 为例:
UISlider *volumeSlider = [[UISlider alloc] initWithFrame:CGRectMake(100, 100, 200, 30)];
volumeSlider.accessibilityValue = [NSString stringWithFormat:@"音量: %.2f", volumeSlider.value];
四、管理无障碍层次结构
- 调整元素在层次结构中的顺序
- 有时候,默认的无障碍层次结构顺序可能不符合用户的操作逻辑。开发者可以通过设置元素的
accessibilityElements
属性来手动调整顺序。 - 假设我们有一个视图包含多个子视图,需要按照特定顺序在无障碍服务中呈现:
- 有时候,默认的无障碍层次结构顺序可能不符合用户的操作逻辑。开发者可以通过设置元素的
UIView *containerView = [[UIView alloc] initWithFrame:self.view.bounds];
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeSystem];
[button1 setTitle:@"按钮 1" forState:UIControlStateNormal];
UIButton *button2 = [UIButton buttonWithType:UIButtonTypeSystem];
[button2 setTitle:@"按钮 2" forState:UIControlStateNormal];
UIButton *button3 = [UIButton buttonWithType:UIButtonTypeSystem];
[button3 setTitle:@"按钮 3" forState:UIControlStateNormal];
containerView.accessibilityElements = @[button1, button3, button2];
- 隐藏不需要的无障碍元素
- 有些视图可能只是用于布局,对用户交互没有实际意义,这些视图不应该出现在无障碍层次结构中。可以通过设置
isAccessibilityElement
属性为NO
来隐藏该元素。 - 例如,一个用于分隔不同区域的 UIView:
- 有些视图可能只是用于布局,对用户交互没有实际意义,这些视图不应该出现在无障碍层次结构中。可以通过设置
UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, 1)];
separatorView.backgroundColor = [UIColor lightGrayColor];
separatorView.isAccessibilityElement = NO;
五、处理无障碍事件
- 监听无障碍聚焦事件
- 当一个无障碍元素获得或失去焦点时,开发者可以通过实现相关代理方法来执行特定的操作。例如,当一个文本字段获得焦点时,显示相关的提示信息。
- 首先,让视图控制器遵循
UIAccessibilityFocusDelegate
协议:
@interface MyViewController : UIViewController <UIAccessibilityFocusDelegate>
@end
- 然后,实现代理方法:
@implementation MyViewController
- (BOOL)accessibilityElementDidBecomeFocused:(UIAccessibilityElement *)element {
if ([element.accessibilityIdentifier isEqualToString:@"my_text_field"]) {
NSLog(@"文本字段获得焦点,显示提示信息");
// 显示提示信息的逻辑
return YES;
}
return NO;
}
- (BOOL)accessibilityElementDidLoseFocus:(UIAccessibilityElement *)element {
if ([element.accessibilityIdentifier isEqualToString:@"my_text_field"]) {
NSLog(@"文本字段失去焦点,隐藏提示信息");
// 隐藏提示信息的逻辑
return YES;
}
return NO;
}
@end
- 处理无障碍操作事件
- 除了默认的操作,开发者还可以为无障碍元素添加自定义的操作。例如,为一个视图添加“双击放大”的无障碍操作。
- 首先,创建一个自定义的无障碍操作:
UIAccessibilityCustomAction *zoomInAction = [[UIAccessibilityCustomAction alloc] initWithName:@"双击放大" target:self selector:@selector(zoomIn:)];
- 然后,将该操作添加到视图的无障碍操作数组中:
UIView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"big_image"]];
imageView.accessibilityCustomActions = @[zoomInAction];
- 最后,实现操作的具体方法:
- (BOOL)zoomIn:(UIAccessibilityCustomAction *)action {
// 放大图片的逻辑
NSLog(@"执行双击放大操作");
return YES;
}
六、适配不同的无障碍模式
- VoiceOver 模式
- VoiceOver 是 iOS 系统中最常用的屏幕阅读器。开发者需要确保在 VoiceOver 模式下,所有无障碍元素的信息准确、清晰,并且导航逻辑合理。
- 例如,对于复杂的表格视图,需要为每一行和每一列设置合适的无障碍标签,以便 VoiceOver 能够准确地向用户描述表格内容。
- 以 UITableView 为例:
@interface MyTableViewController : UITableViewController
@end
@implementation MyTableViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:@"行 %ld", (long)indexPath.row];
cell.accessibilityLabel = [NSString stringWithFormat:@"第 %ld 行,内容:%@", (long)indexPath.row, cell.textLabel.text];
return cell;
}
@end
- 缩放模式
- 缩放模式允许用户放大屏幕内容以便更清晰地查看。开发者需要确保在缩放模式下,应用的布局仍然合理,所有元素仍然可操作。
- 可以通过设置视图的
contentMode
属性来确保图片等元素在缩放时能够正确显示。例如:
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"example_image"]];
imageView.contentMode = UIViewContentModeScaleAspectFit;
- 切换控制模式
- 切换控制模式适用于肢体残疾用户,他们可以通过外部设备(如开关)来控制设备。开发者需要确保应用在切换控制模式下,元素的焦点切换和操作逻辑清晰、易用。
- 可以通过合理设置元素的
accessibilityTraits
属性来影响切换控制模式下元素的行为。例如,对于一个不可点击的标签,设置其accessibilityTraits
为UIAccessibilityTraitStaticText
,这样在切换控制模式下它不会被视为可操作元素。
UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 30)];
myLabel.text = @"这是一个静态标签";
myLabel.accessibilityTraits = UIAccessibilityTraitStaticText;
七、测试无障碍功能
- 使用 VoiceOver 进行手动测试
- 在设备或模拟器上启用 VoiceOver 功能,通过手势操作来模拟视力障碍用户与应用的交互。例如,使用单指轻点来激活元素,双指轻点来执行默认操作等。
- 检查每个无障碍元素的标签、提示、值等信息是否准确,导航顺序是否合理。
- 使用 Instruments 进行自动化测试
- Instruments 工具中的 Accessibility Inspector 可以帮助开发者自动化检测应用的无障碍问题。它可以扫描应用中的所有无障碍元素,检查是否存在缺失的无障碍信息、不合理的层次结构等问题。
- 打开 Instruments,选择 Accessibility Inspector 模板,然后运行应用。Accessibility Inspector 会实时显示应用的无障碍层次结构,并标记出存在问题的元素。
八、最佳实践与注意事项
- 保持一致性
- 在整个应用中,使用一致的无障碍标签、提示和操作逻辑。例如,所有按钮的标签应该简洁明了,并且遵循相同的命名规范。
- 对于相似功能的元素,如不同页面上的确认按钮,它们的无障碍提示应该相同,以便用户能够形成统一的操作习惯。
- 避免过度复杂
- 虽然 UIAccessibility 提供了丰富的功能,但不要过度使用,导致无障碍层次结构过于复杂。尽量保持简单直接的导航和操作方式,让残障用户能够轻松理解和使用应用。
- 例如,避免在一个视图中设置过多的自定义无障碍操作,以免用户感到困惑。
- 实时更新无障碍信息
- 当应用中的元素状态发生变化时,要及时更新其无障碍信息。例如,当一个开关从关闭状态变为打开状态时,其无障碍值和提示应该相应更新。
- 以 UISwitch 为例:
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(100, 100, 0, 0)];
[mySwitch addTarget:self action:@selector(switchValueChanged:) forControlEvents:UIControlEventValueChanged];
- (void)switchValueChanged:(UISwitch *)sender {
if (sender.isOn) {
sender.accessibilityValue = @"已打开";
sender.accessibilityHint = @"再次点击关闭";
} else {
sender.accessibilityValue = @"已关闭";
sender.accessibilityHint = @"再次点击打开";
}
}
- 考虑不同残障类型的需求
- 除了视力障碍用户,还要考虑肢体残疾、听力障碍等其他残障类型用户的需求。例如,为视频添加字幕,确保应用的操作可以通过键盘或其他辅助输入设备完成。
- 对于肢体残疾用户,要确保元素的点击区域足够大,方便操作。可以通过设置视图的
accessibilityFrame
属性来扩大元素的可点击范围。
UIButton *smallButton = [UIButton buttonWithType:UIButtonTypeSystem];
[smallButton setTitle:@"小按钮" forState:UIControlStateNormal];
CGRect enlargedFrame = CGRectInset(smallButton.frame, -20, -20);
smallButton.accessibilityFrame = enlargedFrame;
通过以上全面的介绍,开发者可以在 Objective - C 开发的应用中有效地实现 UIAccessibility 无障碍功能,为残障用户提供更友好、更平等的使用体验。从基础概念到具体配置,再到测试和最佳实践,每个环节都紧密相连,共同构成了一个完整的无障碍应用开发体系。希望开发者能够重视无障碍功能开发,让更多用户受益于我们的应用程序。