12、iOS 开发:动画、自定义控件与无障碍设计

iOS 开发:动画、自定义控件与无障碍设计

1. 动画与直接操作

在 iOS 应用开发中,反馈是向用户传达信息的重要方式,而动画就是一种很好的反馈形式。例如,在动物详情视图中添加动画效果(在模拟器或设备上查看效果最佳)。你可以尝试移除 .animation(_:value:) 修改器,然后点击心形图标,这样就能对比有无动画时的不同效果。

直接操作是用户与应用交互的最直接方式。用户可以通过点击、滑动和手势等操作来控制应用中的各种视图和控件。开发者还可以在此基础上进一步引入结合了多种操作的功能。

2. 自定义控件
2.1 何时不应创建自定义控件

苹果提供了丰富的内置控件,并且这些控件经过了优化和测试,用户也比较熟悉。例如, UIKit UITableView 包含两个委托对象来填充和设置表格样式,苹果在幕后处理表格的渲染,它具有高度优化的渲染性能,还包含许多内置控件,如滑动删除功能。如果试图复制 UITableView 的所有功能和优化,会浪费大量时间。所以,当已有的内置控件能够满足需求时,就不应创建自定义控件。

2.2 何时应创建自定义控件

虽然 iOS 有很多优化的内置控件,但在以下情况下,你可能需要开发自己的控件:
- 自定义交互 :应用可能有特定的交互需求。例如,网络广播应用可能需要模拟汽车收音机的控件,这就需要旋转旋钮,而这在 iOS 中并非内置控件。
- 自定义行为 :当用户与控件交互时,你可能希望包含更符合应用外观和感觉的自定义行为。
- 自定义外观 :iOS 提供了一些 API 让开发者自定义内置控件的外观,但如果这些 API 不能满足需求,或者控件存在显示问题,你可能需要自定义控件。你还可以自定义控件以匹配应用的整体主题。

3. 向 PetSave 添加自定义控件

你将为 PetSave 添加一个排名控件,让用户对宠物详情提供反馈,并指定他们收养该宠物的可能性。为了实现这一目标,你将使用以下技术:
- SwiftUI 视图 :整体视图是一个 HStack 中的一系列 Image 视图。
- 手势 :当用户点击单个 Image 时,它将适当地调整其他 Image 的不透明度,并更新当前排名。

具体操作步骤如下:
1. 打开 Core/views 并创建一个名为 PetRankingView.swift 的新 SwiftUI 视图。
2. 用以下代码替换 PetRankingView 的当前实现:

import SwiftUI
struct PetRankingView: View {
  // 1
  @ObservedObject var viewModel: PetRankingViewModel
  var animal: AnimalEntity
  // 2
  init(animal: AnimalEntity) {
    self.animal = animal
    viewModel = PetRankingViewModel(animal: animal)
  }
  // 3
  var body: some View {
    HStack {
      Text("Rank me!")
        .multilineTextAlignment(.center)
      ForEach(0...4, id: \.self) { index in
        PetRankImage(index: index, recentIndex: $viewModel.ranking)
      }
    }
  }
}

这段代码的作用如下:
- PetRankingViewModel 是一个 @ObservedObject ,它会响应模型中已发布元素的变化。
- init 方法设置 animal 并初始化 PetRankingViewModel
- body 由一个 Text 标签和五个 PetRankImage 组成,它们排列在一个 HStack 中。

  1. PetRankingView 下面添加以下代码:
struct PetRankImage: View {
  let index: Int
  // 1
  @State var opacity: Double = 0.4
  @State var tapped = false
  @Binding var recentIndex: Int
  var body: some View {
    // 2
    Image("creature_dog-and-bone")
      .resizable()
      .aspectRatio(contentMode: .fit)
      .opacity(opacity)
      .frame(width: 50, height: 50)
      .onTapGesture {
        opacity = tapped ? 0.4 : 1.0
        tapped.toggle()
        recentIndex = index
      }
      .onChange(of: recentIndex) { value in
        checkOpacity(value: value)
      }
      .onAppear {
        checkOpacity(value: recentIndex)
      }
  }
  // 3
  func checkOpacity(value: Int) {
    opacity = value >= index ? 1.0 : 0.4
    tapped.toggle()
  }
}

PetRankImage 视图封装了一张狗拿着骨头的图片,并控制图片的不透明度以显示启用状态。这段代码的作用如下:
- opacity tapped @State 属性,用于跟踪该图片是否启用,从而影响整体排名。 recentIndex 是一个 @Binding ,来自父控件,用于确定该图片是否启用。
- Image 具有 opacity onTapGesture onChange 修改器,用于根据用户交互更改状态。
- checkOpacity 根据传入的 recentIndex 更新图片的不透明度。

  1. PetRankImage 结构体下面添加:
final class PetRankingViewModel: ObservableObject {
  var animal: AnimalEntity
  // 1
  var ranking: Int {
    didSet {
      animal.ranking = Int32(ranking)
      objectWillChange.send()
    }
  }
  // 2
  init(animal: AnimalEntity) {
    self.animal = animal
    self.ranking = Int(animal.ranking)
  }
}

PetRankingViewModel 监控用户选择的当前排名,并将该值设置为 animal ranking 属性。需要注意的是:
- ranking 属性有一个 didSet 方法,它使用 objectWillChange.send() 向模型的监听器发布更改。
- init 方法根据传入的 animal 属性初始化 animal ranking 属性。

  1. 更新 PetRankingView_Previews 结构体,使用测试动物实体填充 PetRankingView ,并添加 padding previewLayout 修改器来自定义预览:
struct PetRankingView_Previews: PreviewProvider {
  static var previews: some View {
    if let animal = CoreDataHelper.getTestAnimalEntity() {
      PetRankingView(animal: animal)
        .padding()
        .previewLayout(.sizeThatFits)
    }
  }
}

在预览面板中点击“Resume”,你将看到自定义控件。播放预览,点击控件中低不透明度的狗图标来设置该动物的评级。

  1. 最后,将自定义控件添加到应用中。打开 AnimalDetails/view ,在 AnimalDetailsView.swift 中,在第一个 Divider AnimalDetailRow 之间添加以下代码:
PetRankingView(animal: animal)
  .padding()
  .blur(radius: zoomed ? 20 : 0)

这里你传递了要评级的 animal PetRankingView ,并添加了两个修改器: padding(_:_:) 用于添加间距, .blur(radius:opaque:) 根据 zoomed 的状态设置模糊半径为 20 或 0。构建并运行应用,现在你可以与自定义控件交互来对查看的宠物进行排名。

4. 设计可访问性的原因

设计应用时考虑可访问性非常重要,以下两个统计数据可能会让你感到惊讶:
- 根据美国疾病控制与预防中心(CDC)的数据,美国每四个成年人中就有一个有某种类型的残疾。
- 目前的估计表明,每 12 名男性中就有 1 名(即 8%)患有色盲。

很多人有隐形残疾,如色盲。如果将每四人中有一人有残疾这一统计数据推广到全世界,那么可能有很多人在使用你的应用时会遇到困难。当你使用可访问性技术时,应用将:
- 更具可访问性 :这一点从名称上就可以看出,更多的人可以下载和使用你的应用。
- 更具吸引力 :当残疾用户能够使用应用的更多功能时,他们可能会选择你的应用而不是其他应用。相反,如果应用没有可访问性功能,可能会被这些用户忽略。

5. 苹果人机界面指南中的最佳实践

在设计应用时,应遵循苹果人机界面指南(HIG)中的三个总体原则:
- 为可访问性而设计 :软件工程项目通常将设计放在开发过程的早期,因为设计是需求收集的直接结果。在设计过程中融入可访问性,目标是让应用不仅对残疾人士可用,而且对尽可能多的人可用。HIG 强调了两个重点领域:
- 简单性 :熟悉的交互方式,使任务简单直接。
- 可感知性 :用户可以通过多种感官(如视觉、听觉和触觉)与应用进行交互。
- 支持适应性 :使用苹果的内置用户界面元素可以自动获得这些元素的可访问性支持。你仍然需要在需要的地方提供详细信息,但与整体可访问性框架的连接已经存在。更好的是,这些元素会响应系统范围的可访问性设置,如粗体文本,并相应地进行调整。你还可以轻松地为自定义用户界面元素添加可访问性功能,使 VoiceOver 等工具能够识别并向用户呈现这些元素。
- 测试 :无论你是刚开始开发还是已经有多个应用在 App Store 上,都应该熟悉测试。Xcode 提供了内置的单元测试和用户界面测试目标,并且可以与自动化构建系统一起执行这些测试。当将可访问性技术集成到应用中时,你需要更进一步。打开可访问性功能后,你可以探索用户与应用交互的替代方法,发现需要从可访问性角度改进的区域,甚至可能找到改进应用整体用户体验的区域。你应该在启用可访问性功能(如 VoiceOver)的情况下运行应用的每个用例,观察应用的行为以及用户是否能够轻松完成该用例。Xcode 中的可访问性检查器可以帮助你进行这项工作。

6. 文本与动态类型

应用使用文本向用户传达重要信息,iOS 提供了两种技术来帮助你和用户控制屏幕上文本的外观:动态类型和字体粗细。

6.1 动态类型

在 iOS 7 中,苹果将动态类型添加到 iOS SDK 中。动态类型具有以下特点:
- 可调整文本大小 :用户可以启用动态类型来系统地调整屏幕上的文本大小。想要在屏幕上显示更多文本的用户可以将字体调小,而有视力问题的用户可以增大字体大小,使文本更易于阅读。
- 应用需添加支持 :虽然动态类型的开关是系统范围的,但只有使用动态类型字体的系统才会响应操作系统的调用。

你可以通过进入“设置”中的“可访问性”设置,打开“显示与文字大小”类别,切换“更大字体”并选择你喜欢的文本大小来启用动态类型。你也可以在预览画布中使用 .environment 修改器启用动态类型:

ContentView()
  .environment(\.sizeCategory, .extraLarge)

你使用 \.sizeCategory 键路径来访问预览的动态类型大小, .extraLarge 值设置文本大小。在利用此功能之前,你仍然需要在应用中启用动态类型支持。

在使用动态类型时,需要注意以下几点:
- 避免截断 :当用户增大动态类型大小,文本大小会增加,但设备屏幕大小不会随之增加。因此,如果文本变得太大,就有被截断的风险。在标签中使用 numberOfLines 属性可以让系统自动垂直扩展标签。
- 必要时调整布局 :如果用户界面复杂,较大的文本大小可能会使界面的某些区域难以阅读。你可能需要调整用户界面的布局以适应较大的文本大小。例如,将水平布局(如 HStack )转换为垂直布局(如 VStack )可以防止某些元素被截断。
- SF 符号是动态的 :不仅文本会响应动态类型,SF 符号也可以随着屏幕上的文本一起增大或缩小。

综上所述,在 iOS 应用开发中,合理运用动画、自定义控件和可访问性技术,能够提升用户体验,使应用更具吸引力和包容性。通过遵循苹果的人机界面指南,开发者可以创建出既美观又易用的应用。

iOS 开发:动画、自定义控件与无障碍设计(续)

7. 动态类型在 PetSave 中的应用

在 PetSave 项目中,我们可以进一步展示动态类型的应用。

首先,打开 PetSave/Core/views 并打开 PetRanking.swift 文件。更新文件底部的预览块代码如下:

struct PetRankingView_Previews: PreviewProvider {
  static var previews: some View {
    if let animal = CoreDataHelper.getTestAnimalEntity() {
      Group {
        PetRankingView(animal: animal)
          .padding()
          .previewLayout(.sizeThatFits)
          .environment(\.sizeCategory, .extraSmall)
          .previewDisplayName("Extra - Small")
        PetRankingView(animal: animal)
          .padding()
          .previewLayout(.sizeThatFits)
          .previewDisplayName("Regular")
        PetRankingView(animal: animal)
          .padding()
          .previewLayout(.sizeThatFits)
          .environment(\.sizeCategory, .extraLarge)
          .previewDisplayName("Extra - Large")
      }
    }
  }
}

这段代码添加了几个额外的预览,展示了 .extraSmall .extraLarge 动态类型大小。点击预览画布上的“Resume”(如果需要),你将看到不同的字体大小。

为了更清晰地理解动态类型的影响,我们可以用表格展示不同大小的效果:
| 动态类型大小 | 显示效果 |
| ---- | ---- |
| .extraSmall | 文本和 SF 符号变小,适合需要显示更多内容的场景 |
| Regular | 正常大小,符合大多数用户的日常使用习惯 |
| .extraLarge | 文本和 SF 符号变大,方便视力有困难的用户查看 |

8. 可访问性技术的实际应用流程

为了确保应用的可访问性,我们可以按照以下流程进行操作:

graph LR
    A[开始开发应用] --> B[遵循可访问性设计原则]
    B --> C[使用苹果内置控件获取基础支持]
    C --> D[为自定义控件添加可访问性功能]
    D --> E[集成动态类型等可访问性技术]
    E --> F[进行可访问性测试]
    F --> G{是否通过测试?}
    G -- 是 --> H[发布应用]
    G -- 否 --> I[改进可访问性问题]
    I --> F

具体步骤如下:
1. 遵循可访问性设计原则 :在开发过程中,始终牢记简单性和可感知性原则,确保用户可以轻松地与应用进行交互。
2. 使用苹果内置控件 :利用苹果提供的内置用户界面元素,自动获得这些元素的可访问性支持。
3. 为自定义控件添加可访问性功能 :对于自定义的用户界面元素,添加必要的信息,使 VoiceOver 等工具能够识别并向用户呈现这些元素。
4. 集成可访问性技术 :如动态类型,让用户可以根据自己的需求调整文本大小。
5. 进行可访问性测试 :在启用可访问性功能(如 VoiceOver)的情况下运行应用的每个用例,使用 Xcode 中的可访问性检查器来发现问题。
6. 改进问题 :根据测试结果,对发现的可访问性问题进行改进。
7. 发布应用 :当应用通过可访问性测试后,将其发布到 App Store。

9. 自定义控件与可访问性的结合

在前面我们为 PetSave 添加了自定义的排名控件,现在我们来考虑如何将可访问性与这个自定义控件结合起来。

对于 PetRankingView PetRankImage ,我们可以添加可访问性标签和提示。例如,在 PetRankImage 中,我们可以修改代码如下:

struct PetRankImage: View {
  let index: Int
  @State var opacity: Double = 0.4
  @State var tapped = false
  @Binding var recentIndex: Int

  var body: some View {
    Image("creature_dog - and - bone")
      .resizable()
      .aspectRatio(contentMode: .fit)
      .opacity(opacity)
      .frame(width: 50, height: 50)
      .onTapGesture {
        opacity = tapped ? 0.4 : 1.0
        tapped.toggle()
        recentIndex = index
      }
      .onChange(of: recentIndex) { value in
        checkOpacity(value: value)
      }
      .onAppear {
        checkOpacity(value: recentIndex)
      }
      .accessibilityLabel("Rank \(index + 1)")
      .accessibilityHint("Tap to set the ranking for the pet.")
  }

  func checkOpacity(value: Int) {
    opacity = value >= index ? 1.0 : 0.4
    tapped.toggle()
  }
}

通过添加 accessibilityLabel accessibilityHint ,VoiceOver 等工具可以更好地向有视力障碍的用户解释这个控件的功能。

10. 总结

在 iOS 开发中,动画、自定义控件和可访问性是提升应用质量和用户体验的重要方面。

动画可以作为一种有效的反馈方式,让用户更直观地感受到应用的状态变化。自定义控件则可以满足应用特定的交互需求,为用户提供独特的体验,但需要谨慎使用,避免不必要的重复开发。

可访问性设计是现代应用开发中不可或缺的一部分。考虑到全球有大量的残疾人士,为应用添加可访问性功能不仅可以让更多的人使用你的应用,还可以提高应用的吸引力。通过遵循苹果人机界面指南中的最佳实践,如设计简单的交互、支持动态类型、进行充分的测试等,开发者可以创建出更加包容和易用的应用。

同时,我们也看到了如何将这些技术结合起来,例如在自定义控件中添加可访问性信息,以及在应用中集成动态类型。这些技术的综合应用将有助于开发者打造出高质量的 iOS 应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值