版本记录
版本号 | 时间 |
---|---|
V1.0 | 2022.04.05 星期二 清明节 |
前言
3D Touch
是iPhone 6s+
,iOS9+
之后新增的功能。其最大的好处在于不启动app的情况下,快速进入app中的指定界面,说白了,就是一个快捷入口。接下来几篇我们就一起看下相关的内容。
开始
首先看下主要内容:
了解如何将静态和动态主屏幕快速操作
(Static and Dynamic Home Screen Quick Actions)
集成到您的SwiftUI iOS
应用中。内容来自翻译。
接着看下写作环境:
Swift 5.5, iOS 15, Xcode 13
快捷操作(Quick actions)
是让您的用户在主屏幕中快速访问您应用的常用功能的好方法。 iOS 13 引入了Quick actions
的概念,用户可以在其中触摸并按住应用程序图标以显示一组快捷方式或操作(shortcuts or actions)
,以便直接从主屏幕执行。
默认情况下,所有应用程序都具有编辑主屏幕或删除应用程序的快捷操作:
开发者还可以提供自己的快捷操作,为用户提供常用应用功能的强大快捷方式。 iOS 相机应用程序具有拍摄不同类型的照片或录制视频的操作。购物应用程序可能会让您直接跳转到您的订单或愿望清单,而消息传递应用程序可能会显示您最喜欢的联系人,以便您轻松访问它们。
我相信您可以想出快捷操作可以使您的用户受益的方式。在本教程中,您将了解:
- 静态快速操作
(Static quick actions,)
,始终可用于您的应用。 - 动态快速操作
(Dynamic quick actions)
,您的应用可以在运行时定义。 - 如何在示例项目中支持这两种类型的快速操作,一个名为
Note Buddy
的笔记应用程序。
入门
打开下载好的程序,Note Buddy
是一款具有一些基本功能的笔记应用程序:
- 添加、编辑或删除带有标题和正文的笔记。
- 收藏一个笔记。
- 在启动之间存储您的笔记。
- 按上次修改日期自动排序笔记。
打开项目,然后构建并运行。你会看到这个笔记页面:
为了增强 Note Buddy
的功能,您可以在 Models
组中找到 Note
模型及其关联的 NoteStore
类。
转到 SwiftUI
,在 Views
组中,您有:
-
NoteList
:显示按上次修改日期排序的所有笔记列表。 -
NoteRow
:笔记列表中笔记行的视图。它显示笔记的标题、正文以及用户是否将其标记为收藏。 -
EditNote
:用于修改笔记标题、正文或更改收藏状态的编辑器。 -
NavigationLink+Value
:一个辅助扩展,当你有一个关联的数据模型要Push
时,使编程导航更容易一些。
最后,AppMain
使用对 NoteStore
的引用和在 WindowGroup
中设置 NoteList
视图并正确注入适当环境值的主体来描述您的应用程序。
在你开始编码之前,是时候仔细看看这两种类型的快速操作是什么,以及它们是如何工作的。
Static vs. Dynamic Quick Actions
您可以使用两种类型的快速操作:静态和动态。
您将静态操作用于在您的应用程序中永远不会更改的操作,例如Mail
应用程序的New Message
操作。
如果您的操作可能在某些条件下发生变化或取决于特定数据或状态,请使用dynamic actions
。例如,Messages app
将为您所有固定的对话添加快速操作。
在这两种情况下,您都添加代码来处理触发的特定操作。由于添加静态快速操作更快,您将从这些开始。
Creating Static Quick Actions
静态快速操作是让您的用户创建新笔记的好方法。
首先,添加模型代码以帮助您处理触发的操作。 右键单击 Models
组,然后单击 New File... ▸ Swift File
。 将新文件命名为 Action
并单击 Create
。
将文件内容替换为:
import UIKit
// 1
enum ActionType: String {
case newNote = "NewNote"
}
// 2
enum Action: Equatable {
case newNote
// 3
init?(shortcutItem: UIApplicationShortcutItem) {
// 4
guard let type = ActionType(rawValue: shortcutItem.type) else {
return nil
}
// 5
switch type {
case .newNote:
self = .newNote
}
}
}
// 6
class ActionService: ObservableObject {
static let shared = ActionService()
// 7
@Published var action: Action?
}
很多事情正在发生。这是您添加的内容:
- 1) 您创建一个由
String
支持的名为ActionType
的枚举。稍后您将使用字符串值来帮助识别您的应用将执行的不同类型的操作。newNote case
将识别创建新笔记的操作。 - 2) 您创建另一个名为
Action
的枚举,它看起来相似,但只是Equatable
。这可能看起来有点重复,但是当您稍后添加其他操作时它会很有意义。 - 3) 然后创建一个可失败的初始化程序,它接受
UIApplicationShortcutItem
的实例。系统使用这种类型来描述不同的快速动作。 - 4) 在这里,您确保为已知的
ActionType
创建一个Action
,否则返回nil
。 - 5) 打开您的应用已知的不同可能的
ActionType
值。然后,您可以使用可用信息来描述正确的Action
。 - 6) 定义一个
ObservableObject
类,您可以稍后将其传递到SwiftUI
环境中,并为以后使用UIKit
代码时提供一个单例访问器。 - 7) 定义一个
@Published
属性,该属性可以表示您的应用应执行的操作。
Action
概念的目的是让您对应用程序支持的快速操作进行建模,并在 UIApplicationShortcutItem
之间进行映射时安全地使用它们。
现在,打开 AppMain.swift
。在 noteStore
上方,为 ActionService
添加一个新属性:
private let actionService = ActionService.shared
然后更新 body
实现以确保服务被注入到视图层次结构中并且 NoteList
可以访问它:
var body: some Scene {
WindowGroup {
NoteList()
.environmentObject(actionService)
.environmentObject(noteStore)
.environment(\.managedObjectContext, noteStore.container.viewContext)
}
}
ActionService
在 SwiftUI
环境中可用,是时候使用它了。 在 Views
组中打开 NoteList.swift
并在 noteStore
下添加以下属性:
@EnvironmentObject var actionService: ActionService
@Environment(\.scenePhase) var scenePhase
您不仅要访问 ActionService
类,还需要访问 ScenePhase
,该属性会在您的应用程序变为活动状态以及进入后台时通知您。
在视图的底部,添加以下方法:
func performActionIfNeeded() {
// 1
guard let action = actionService.action else { return }
// 2
switch action {
case .newNote:
createNewNote()
}
// 3
actionService.action = nil
}
这个方法做了三件事:
- 1) 检查
ActionService
中是否有动作。 - 2) 打开动作类型并为
Action.newNote
调用createNewNote()
动作。 - 3) 从
ActionService
中删除操作,因为它已被执行。
每当您的应用程序处于活动状态时,您都需要触发此代码。 您将使用 onChange(of:perform:)
视图修饰符和之前添加的 scenePhase
属性。
在toolbar
修饰符的右大括号后添加以下代码:
// 1
.onChange(of: scenePhase) { newValue in
// 2
switch newValue {
case .active:
performActionIfNeeded()
// 3
default:
break
}
}
在这里,代码:
- 1) 向
List
添加一个修改器,该修改器将在scenePhase
更改时触发其闭包。 - 2) 使用提供的参数,它会打开该值。 如果它是
.active
,它会调用你的新performActionIfNeeded()
方法。 - 3) 由于您不关心其他状态,例如
.inactive
或.background
,它不会做任何事情。
1. Modifying the Info Property List File
您将逻辑添加到处理操作的代码中。 但在运行应用程序之前,您仍然需要告诉系统您的静态操作。 这很简单。
在Resources
组中,打开 Info.plist
。 右键单击顶部的Information Property List
,然后单击Add Row
。
在 Key
列中,键入 Home Screen Shortcut Items
,然后按回车键完成编辑。 Xcode
自动将 Type
设置为 Array
并为您添加一个项目。 通过单击 V
形展开元素,您将看到两个嵌套键:
此数组中列出的每个项目代表您的应用支持的单个静态快速操作。使用以下值更新占位符项:
Shortcut Item Type: NewNote
Title: New Note
除了默认键之外,您还需要添加一个。将鼠标悬停在标题上,然后单击出现的 +
图标。键入 UIApplicationShortcutItemIconSymbolName
(暂时忽略弹出选项,您必须键入完整的字符串)作为键和 square.and.pencil
作为值。
以下是每个键的细分:
-
Shortcut Item Type - 快捷方式项目类型:表示唯一类型操作的字符串标识符。您可能会注意到这与您之前添加的
ActionType.newNote
枚举案例的原始值相匹配。这很重要。 - Title - 标题:当用户点击并按住您的应用程序图标时显示的用户友好标题。
-
UIApplicationShortcutItemIconSymbolName:用于此操作的
SF
符号。您还可以使用UIApplicationShortcutItemIconFile
用于您的包中可用的图标文件,或UIApplicationShortcutItemIconType
用于一组可用于快速操作的预定义选项。编辑Info.plist
条目时,可以从下拉列表中选择图标文件和图标类型,但符号选项不是。
您可以在 Apple documention中阅读 Info.plist
中的快捷方式项目还有其他可用的键。
2. Building and Running Your App
构建并运行您的应用程序。 返回主屏幕并长按 Note Buddy
应用程序图标以查看列表中现在可用的快速操作:
点击New Note
以查看会发生什么:
没有?!?
嗯,这很奇怪。 您添加了一个模型来处理应用程序中的操作,并在 Info.plist
中定义了一个静态操作。
这是出了什么问题?
当用户与快速操作进行交互时,系统会告诉您的应用程序,但您还没有对这些信息做任何事情。 是时候这样做了!
3. Handling Static Quick Actions
SwiftUI
还没有提供任何原生机制来响应快速操作的启动事件。 因此,这部分需要依赖 UIKit
。
右键单击 AppMain.swift
并选择 New File... ▸ Swift File
。 将文件命名为 AppDelegate
并单击Create
。 将文件内容替换为:
// 1
import UIKit
// 2
class AppDelegate: NSObject, UIApplicationDelegate {
private let actionService = ActionService.shared
// 3
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
// 4
if let shortcutItem = options.shortcutItem {
actionService.action = Action(shortcutItem: shortcutItem)
}
// 5
let configuration = UISceneConfiguration(
name: connectingSceneSession.configuration.name,
sessionRole: connectingSceneSession.role
)
configuration.delegateClass = SceneDelegate.self
return configuration
}
}
// 6
class SceneDelegate: NSObject, UIWindowSceneDelegate {
private let actionService = ActionService.shared
// 7
func windowScene(
_ windowScene: UIWindowScene,
performActionFor shortcutItem: UIApplicationShortcutItem,
completionHandler: @escaping (Bool) -> Void
) {
// 8
actionService.action = Action(shortcutItem: shortcutItem)
completionHandler(true)
}
}
如果你对 UIKit
不太熟悉,别担心!以下是上述代码的概述:
- 1) 导入
UIKit
框架以访问此文件中所需的符号和类型。 - 2) 创建一个名为
AppDelegate
的类,它继承自NSObject
并符合UIApplicationDelegate
协议。 - 3) 实现
application(_:configurationForConnecting:options:)
以hook
进入应用程序准备启动主 UI 时触发的事件。 - 4) 解包随选项提供的
shortcutItem
项。如果存在,则表明用户正在通过快速操作启动您的应用程序。使用您之前添加的初始化程序将数据映射到Action
并将其分配给ActionService
。 - 5) 通过创建适当的
UISceneConfiguration
对象并返回它来满足该方法的要求。 - 6) 与第二步类似,创建另一个符合
UIWindowSceneDelegate
协议的类。 - 7) 实现
windowScene(_:performActionFor:completionHandler:)
以hook
进入在您的应用程序启动后用户与快速操作交互时触发的事件,例如,当它在后台时。 - 8) 与第四步类似,尝试将
UIApplicationShortcutItem
转换为Action
并将其传递给ActionService
。
最后,您的 SwiftUI
应用需要使用新的 AppDelegate
和 SceneDelegate
。因此,在 AppMain.swift
中的 actionService
下方,在 AppMain
中添加以下属性:
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
是时候再次构建和运行您的应用程序了。 返回主屏幕并再次尝试使用您的快速操作:
极好的! 您添加了您的第一个静态快速操作。 虽然这为许多可能性打开了大门,但您无法使用运行时使用的信息对其进行自定义。 这就是动态操作的用武之地。
Creating Dynamic Quick Actions
如果用户想要编辑他们最近的笔记,他们仍然需要打开应用程序,滚动列表以找到它,点击它然后进行编辑。
简化和加快流程会很棒!
在 Info.plist
中进行静态操作时,您可以在代码中添加所有动态操作。 在 Note Buddy
的情况下,可能对于您的许多应用程序,当您的场景的阶段变为background
时,将添加这些动态操作。 因此,在前往主屏幕之前,您可以设置一些操作以在最近修改日期之前编辑最新的笔记。
1. Handling Dynamic Quick Actions
要添加动态操作,首先将一个新case
添加到您的 ActionType
和 Action
枚举中。
打开 Action.swift
并将以下内容添加到 ActionType
中:
case editNote = "EditNote"
将以下新case
添加到Action
:
case editNote(identifier: String)
这就是为什么 ActionType
和 Action
需要是两个独立的枚举。 ActionType
代表不同快速动作类型的标识符,而 Action
代表动作本身。 在某些情况下,例如 .editNote
的case
,它可以包含其他关联值。
添加新的枚举case
后,您会注意到编译器友好地告诉您 init?(shortcutItem:)
中的 switch
语句不再详尽。 通过将以下case
添加到开关来解决此问题:
case .editNote:
if let identifier = shortcutItem.userInfo?["NoteID"] as? String {
self = .editNote(identifier: identifier)
} else {
return nil
}
在这里,您将检查 shortcutItem
的 userInfo
字典以获取要编辑的笔记的 ID
。 如果成功,则将操作初始化为具有关联值的 .editNote
。 否则,初始化程序将通过返回 nil
失败。
如果您现在尝试构建项目,您将在 NoteList.swift
中看到另一个编译失败。 转到它,你会发现你还需要在 performActionIfNeeded()
中实现新的动作处理。
将以下代码添加到 switch
语句中:
case .editNote(let identifier):
selectedNote = noteStore.findNote(withIdentifier: identifier)
构建并运行您的应用程序。 然后前往主屏幕,长按 Note Buddy
图标并查看结果:
再一次……什么都没有?
虽然您已经确保快速操作正确传递到您的应用程序,但您仍然没有告诉您的应用程序显示任何动态项目。 接下来你会这样做。
2. Adding Your Dynamic Quick Actions
如前所述,添加动态操作的好地方是应用程序进入后台时。 此时,您拥有运行代码所需的所有信息,该代码确定要添加哪些操作,然后添加它们。
由于您已经在 NoteList
中观察了 ScenePhase
,因此这是更新动作的好地方。 但在此之前,您需要创建自己的 UIApplicationShortcutItem
实例来描述您的动态操作。
前往 Note.swift
并在文件顶部添加以下import
:
import UIKit
在 Note
扩展中,添加以下属性:
// 1
var shortcutItem: UIApplicationShortcutItem? {
// 2
guard !wrappedTitle.isEmpty || !wrappedBody.isEmpty else { return nil }
// 3
return UIApplicationShortcutItem(
type: ActionType.editNote.rawValue,
localizedTitle: "Edit Note",
localizedSubtitle: wrappedTitle.isEmpty ? wrappedBody : wrappedTitle,
icon: .init(systemImageName: isFavorite ? "star" : "pencil"),
userInfo: [
"NoteID": identifier as NSString
]
)
}
下面是代码分解:
- 1) 您在
Note
上定义了一个名为shortcutItem
的新计算属性。该属性是可选的,因为您不需要将每个笔记都表示为快速操作。 - 2) 如果注释没有标题或正文,则返回
nil
以便不会显示该注释。 - 3) 然后初始化
UIApplicationShortcutItem
的新实例并返回它。- 使用
ActionType
定义的类型,以便在您稍后读回它时与预期值匹配。 - 提供一个用户友好的
title
,就像您在Info.plist
中所做的那样。 - 要进一步个性化操作,您可以将笔记的标题或正文作为快速操作的副标题。
- 使用适当的
SF
符号来表示该项目是否是收藏。 - 在
userInfo
中包含Note
的唯一标识符,以便您在响应快速操作时知道要编辑哪个笔记。
- 使用
现在您已经创建了一个属性来公开给定 Note
的适当快捷方式,请导航回 NoteList.swift
。在 performActionIfNeeded()
下添加以下方法:
func updateShortcutItems() {
UIApplication.shared.shortcutItems = notes.compactMap(\.shortcutItem)
}
在这里,您压缩映射 notes
数组以生成仅包含非nil
的 UIApplicationShortcutItem
的数组。 然后将该数组分配给 UIApplication
的 shortcutItems
属性,该属性又与您在主屏幕菜单中的静态操作一起可用。
现在,您只需在应用程序进入后台时调用此方法。 向上滚动到您之前添加的 onChange(of: perform:)
修饰符,并在 switch
语句中添加以下内容:
case .background:
updateShortcutItems()
构建并运行。 然后看看有哪些项目可用:
Yeah,你做到了。
对您的笔记进行一些编辑,收藏一些并重复该过程。 显示的笔记以及顺序在您后台运行应用程序时保持完美同步:
您可能已经注意到,并非所有笔记都显示出来。 iOS
将操作数量限制为仅显示适合屏幕的操作。但是,文档建议您不要专门限制动态操作的计数。而是,像 Note Buddy
那样做。
这样,iOS 将显示它可以适应的所有快速操作。如果未来的更新能够实现更多功能,那就太好了,因为您无需在后台应用程序之前推出应用程序更新来支持添加更多操作。
如果您想了解更多信息,请查看有关 UIKit 中 Menus and Shortcuts 的 Apple 文档,以及Human Interface Guidelines for Home Screen Quick Actions。
后记
本篇主要讲述了
Home Screen Quick Actions for SwiftUI App
,感兴趣的给个赞或者关注~~~
网友评论