MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C中的UIAccessibility无障碍功能开发

2022-01-121.8k 阅读

一、UIAccessibility 简介

在当今数字化的时代,确保所有用户,包括残障人士,都能平等地使用应用程序至关重要。UIAccessibility 是 iOS 系统中提供的一套强大的无障碍功能框架,它允许开发者使应用程序对残障用户更友好,例如视力障碍者可通过 VoiceOver 屏幕阅读器来理解应用界面,肢体残疾者可以使用辅助输入设备来与应用进行交互。

Objective - C 作为 iOS 开发的传统语言,对 UIAccessibility 的支持非常全面。通过遵循 UIAccessibility 协议和使用相关类与方法,开发者能够将无障碍功能无缝集成到应用中。

二、UIAccessibility 基础概念

  1. 无障碍元素
    • 应用中的每个可交互的视图或控件,如按钮、文本框、标签等,都可以成为一个无障碍元素。这些元素需要向无障碍服务提供足够的信息,例如元素的名称、用途、当前状态等,以便残障用户能够理解并与之交互。
    • 在 Objective - C 中,UIView 及其子类默认支持 UIAccessibility。开发者可以通过设置相关属性来配置无障碍信息。
  2. 无障碍层次结构
    • iOS 系统将应用中的所有无障碍元素组织成一个层次结构。这个层次结构与视图层次结构密切相关,但并不完全相同。无障碍层次结构的遍历顺序决定了 VoiceOver 等无障碍服务按什么顺序向用户介绍界面元素。
    • 开发者需要确保无障碍层次结构的合理性,避免出现混乱的导航顺序,从而给残障用户带来困扰。
  3. 无障碍特征
    • 无障碍特征用于描述元素的行为和状态,例如按钮是否可点击、开关是否打开、文本字段是否可编辑等。通过设置这些特征,开发者可以让无障碍服务准确地向用户传达元素的当前情况。

三、配置无障碍元素

  1. 设置无障碍标识符(Accessibility Identifier)
    • 无障碍标识符是一个字符串,用于唯一标识应用中的一个无障碍元素。这在自动化测试和屏幕阅读器导航中非常有用。
    • 在 Objective - C 中,为视图设置无障碍标识符非常简单,例如:
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeSystem];
myButton.accessibilityIdentifier = @"my_special_button";
  1. 设置无障碍标签(Accessibility Label)
    • 无障碍标签是对元素的简短描述,用于告知用户该元素的用途。对于按钮,标签通常就是按钮上显示的文字,但对于一些非文本类的元素,如图标按钮,需要明确设置标签。
    • 示例代码如下:
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"settings_icon"]];
iconView.accessibilityLabel = @"设置图标";
  1. 设置无障碍提示(AccessibilityHint)
    • 无障碍提示是对用户操作元素后预期结果的简短描述。例如,对于一个删除按钮,可以设置提示为“点击删除当前项目”。
    • 代码示例:
UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeSystem];
[deleteButton setTitle:@"删除" forState:UIControlStateNormal];
deleteButton.accessibilityHint = @"点击删除当前项目";
  1. 设置无障碍值(Accessibility Value)
    • 对于一些有取值的元素,如滑块、进度条等,无障碍值用于向用户传达当前的取值。
    • 以 UISlider 为例:
UISlider *volumeSlider = [[UISlider alloc] initWithFrame:CGRectMake(100, 100, 200, 30)];
volumeSlider.accessibilityValue = [NSString stringWithFormat:@"音量: %.2f", volumeSlider.value];

四、管理无障碍层次结构

  1. 调整元素在层次结构中的顺序
    • 有时候,默认的无障碍层次结构顺序可能不符合用户的操作逻辑。开发者可以通过设置元素的 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];
  1. 隐藏不需要的无障碍元素
    • 有些视图可能只是用于布局,对用户交互没有实际意义,这些视图不应该出现在无障碍层次结构中。可以通过设置 isAccessibilityElement 属性为 NO 来隐藏该元素。
    • 例如,一个用于分隔不同区域的 UIView:
UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, 1)];
separatorView.backgroundColor = [UIColor lightGrayColor];
separatorView.isAccessibilityElement = NO;

五、处理无障碍事件

  1. 监听无障碍聚焦事件
    • 当一个无障碍元素获得或失去焦点时,开发者可以通过实现相关代理方法来执行特定的操作。例如,当一个文本字段获得焦点时,显示相关的提示信息。
    • 首先,让视图控制器遵循 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
  1. 处理无障碍操作事件
    • 除了默认的操作,开发者还可以为无障碍元素添加自定义的操作。例如,为一个视图添加“双击放大”的无障碍操作。
    • 首先,创建一个自定义的无障碍操作:
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;
}

六、适配不同的无障碍模式

  1. 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
  1. 缩放模式
    • 缩放模式允许用户放大屏幕内容以便更清晰地查看。开发者需要确保在缩放模式下,应用的布局仍然合理,所有元素仍然可操作。
    • 可以通过设置视图的 contentMode 属性来确保图片等元素在缩放时能够正确显示。例如:
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"example_image"]];
imageView.contentMode = UIViewContentModeScaleAspectFit;
  1. 切换控制模式
    • 切换控制模式适用于肢体残疾用户,他们可以通过外部设备(如开关)来控制设备。开发者需要确保应用在切换控制模式下,元素的焦点切换和操作逻辑清晰、易用。
    • 可以通过合理设置元素的 accessibilityTraits 属性来影响切换控制模式下元素的行为。例如,对于一个不可点击的标签,设置其 accessibilityTraitsUIAccessibilityTraitStaticText,这样在切换控制模式下它不会被视为可操作元素。
UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 30)];
myLabel.text = @"这是一个静态标签";
myLabel.accessibilityTraits = UIAccessibilityTraitStaticText;

七、测试无障碍功能

  1. 使用 VoiceOver 进行手动测试
    • 在设备或模拟器上启用 VoiceOver 功能,通过手势操作来模拟视力障碍用户与应用的交互。例如,使用单指轻点来激活元素,双指轻点来执行默认操作等。
    • 检查每个无障碍元素的标签、提示、值等信息是否准确,导航顺序是否合理。
  2. 使用 Instruments 进行自动化测试
    • Instruments 工具中的 Accessibility Inspector 可以帮助开发者自动化检测应用的无障碍问题。它可以扫描应用中的所有无障碍元素,检查是否存在缺失的无障碍信息、不合理的层次结构等问题。
    • 打开 Instruments,选择 Accessibility Inspector 模板,然后运行应用。Accessibility Inspector 会实时显示应用的无障碍层次结构,并标记出存在问题的元素。

八、最佳实践与注意事项

  1. 保持一致性
    • 在整个应用中,使用一致的无障碍标签、提示和操作逻辑。例如,所有按钮的标签应该简洁明了,并且遵循相同的命名规范。
    • 对于相似功能的元素,如不同页面上的确认按钮,它们的无障碍提示应该相同,以便用户能够形成统一的操作习惯。
  2. 避免过度复杂
    • 虽然 UIAccessibility 提供了丰富的功能,但不要过度使用,导致无障碍层次结构过于复杂。尽量保持简单直接的导航和操作方式,让残障用户能够轻松理解和使用应用。
    • 例如,避免在一个视图中设置过多的自定义无障碍操作,以免用户感到困惑。
  3. 实时更新无障碍信息
    • 当应用中的元素状态发生变化时,要及时更新其无障碍信息。例如,当一个开关从关闭状态变为打开状态时,其无障碍值和提示应该相应更新。
    • 以 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 = @"再次点击打开";
    }
}
  1. 考虑不同残障类型的需求
    • 除了视力障碍用户,还要考虑肢体残疾、听力障碍等其他残障类型用户的需求。例如,为视频添加字幕,确保应用的操作可以通过键盘或其他辅助输入设备完成。
    • 对于肢体残疾用户,要确保元素的点击区域足够大,方便操作。可以通过设置视图的 accessibilityFrame 属性来扩大元素的可点击范围。
UIButton *smallButton = [UIButton buttonWithType:UIButtonTypeSystem];
[smallButton setTitle:@"小按钮" forState:UIControlStateNormal];
CGRect enlargedFrame = CGRectInset(smallButton.frame, -20, -20);
smallButton.accessibilityFrame = enlargedFrame;

通过以上全面的介绍,开发者可以在 Objective - C 开发的应用中有效地实现 UIAccessibility 无障碍功能,为残障用户提供更友好、更平等的使用体验。从基础概念到具体配置,再到测试和最佳实践,每个环节都紧密相连,共同构成了一个完整的无障碍应用开发体系。希望开发者能够重视无障碍功能开发,让更多用户受益于我们的应用程序。