打造 Apple Watch 笔记应用:功能实现与交互优化
1. 实现新笔记创建与设备通信
首先要实现创建新笔记的功能,这和之前实现的创建文档方法类似,但有一处不同:成功创建文档后,调用
handleListAllNotes
,让 Apple Watch 接收更新后的文档列表。
接着,要让
WCSession
使用应用委托作为其委托,因为应用委托现在能接收并回复来自手表的消息。在
AppDelegate
的
didFinishLaunchingWithOptions
方法中添加以下代码来设置并激活会话:
WCSession.default().delegate = self
WCSession.default().activate()
和在 Apple Watch 上一样,要配置
WCSession
以便在收到消息时能得到通知,同时调用
activateSession
开启两个设备间的双向通信。至此,iPhone 和 Apple Watch 就能相互通信了。
2. 构建 Apple Watch 用户界面
Apple Watch 应用由两个
WKInterfaceController
子类组成,一个显示笔记列表,另一个显示单条笔记内容。
2.1 重命名默认控制器
默认情况下,Xcode 模板有个名为
InterfaceController
的
WKInterfaceController
,为了更好描述其用途,需要重命名:
1. 将
InterfaceController.swift
文件重命名为
NoteListInterfaceController.swift
。
2. 打开该文件,把
InterfaceController
类重命名为
NoteListInterfaceController
。
由于 Apple Watch 应用启动时会查找名为
InterfaceController
的接口控制器类,所以要更改设置:
1. 打开 Watch 扩展的
Info.plist
文件,找到
RemoteInterfacePrincipalClass
条目。
2. 将该条目从
$(PRODUCT_MODULE_NAME).InterfaceController
改为
$(PRODUCT_MODULE_NAME).NoteListInterfaceController
。
2.2 创建新的控制器类
创建控制第二个屏幕(显示笔记内容)的类,每个独立的接口控制器应是独立的类,以便每个屏幕能独立运行:
1. 打开文件菜单,选择
New→File
。
2. 在 watchOS 部分选择
Source
类别,选中
WatchKit class
,点击
Next
。
3. 将新类命名为
NoteInterfaceController
,并使其成为
WKInterfaceController
的子类。
2.3 设置故事板
设置 watchOS 应用使用的故事板:
1. 打开
Interface.storyboard
文件,找到接口控制器并选中。
2. 打开
Identity Inspector
,将其类从
InterfaceController
改为
NoteListInterfaceController
。
3. 打开
Attributes Inspector
,将其标题改为
Notes
。
3. 设计笔记列表界面
笔记列表会显示一系列笔记,在 watchOS 中用表格显示内容列表,表格的每行界面可按需定制。每行内容由自定义的行控制器控制,每种行需要新的行控制器类,这里只需继承通用的
NSObject
类:
1. 到对象库搜索表格,将其拖到接口控制器中,表格会填满屏幕宽度。
2. 创建行控制器类:
- 在辅助编辑器中打开
NoteListInterfaceController.swift
。
- 在文件底部添加
NoteRow
类:
class NoteRow : NSObject {
}
- 在大纲中选中行控制器,打开 `Identity Inspector`,将其类设置为 `NoteRow`。
- 打开 `Attributes Inspector`,将其标识符也设置为 `NoteRow`,用于填充表格内容。
- 在对象库搜索 `Label` 并拖到表格行中,选中新标签,将其文本设置为 `Note Name`。
4. 连接界面与代码
将界面与代码连接起来:
1. 按住
Control
键,从标签拖到
NoteRow
类,创建名为
nameLabel
的新出口。
2. 再次按住
Control
键,从大纲中的表格条目拖到
NoteListInterfaceController
类,创建名为
noteListTable
的新出口。
5. 更新表格内容
将更新表格的代码封装到
updateListWithNotes
方法中:
func updateListWithNotes(_ notes: [SessionManager.NoteInfo]) {
// 检查笔记是否有变化,无变化则不做处理
if notes == self.displayedNotes {
return
}
self.noteListTable.setNumberOfRows(notes.count, withRowType: "NoteRow")
for (i, note) in notes.enumerated() {
if let row = self.noteListTable.rowController(at: i) as? NoteRow {
row.nameLabel.setText(note.name)
}
}
self.displayedNotes = notes
}
在
NoteListViewController
中添加
willActivate
方法,在界面控制器显示时获取笔记列表并更新表格:
override func willActivate() {
SessionManager.sharedSession.updateList() { notes, error in
self.updateListWithNotes(notes)
}
}
运行应用,笔记列表就会显示出来。
6. 显示笔记内容
创建显示单条笔记内容的新接口控制器,用户点击
NoteListInterfaceController
中的笔记时,通过 segue 过渡到该控制器,它会从 iPhone 请求笔记文本并显示在标签中。
6.1 创建新控制器界面
-
到对象库搜索
Interface Controller,选择基础的Interface Controller拖入。 -
选中它,打开
Identity Inspector,将其类从WKInterfaceController改为NoteInterfaceController。 -
打开
Attributes Inspector,将其标题改为Note。
6.2 创建 segue
-
按住
Control键,从表格视图中的单行拖到笔记接口控制器,释放鼠标后选择Push类型的 segue。 -
选中新 segue,打开
Attributes Inspector,将其标识符改为ShowNote。
6.3 设计控制器界面
- 拖一个标签到接口控制器中。
-
打开
Attributes Inspector,将Lines值设为 0,让标签能调整大小以适应所有文本。 -
将
Text值设为Note Content,运行时该文本会被实际笔记内容替换。
6.4 连接标签与代码
在辅助编辑器中打开
NoteInterfaceController
,按住
Control
键,从
Note Content
标签拖到
NoteInterfaceController
类,创建名为
noteContentLabel
的新出口。运行应用,点击笔记就会进入新界面。
6.5 传递笔记 URL
在
NoteListInterfaceController.swift
中添加
contextForSegue
方法:
override func contextForSegue(withIdentifier segueIdentifier: String,
in table: WKInterfaceTable, rowIndex: Int) -> Any? {
// 检查是否为 ShowNote segue
if segueIdentifier == "ShowNote" {
// 将选中笔记的 URL 传递给接口控制器
return SessionManager.sharedSession.notes[rowIndex].URL
}
return nil
}
在
NoteInterfaceController.swift
中更新
awakeWithContext
方法:
override func awake(withContext context: Any?) {
// 希望接收到指向 iPhone 上笔记的 NSURL
if let url = context as? URL {
// 先清空标签
self.noteContentLabel.setText(nil)
SessionManager.sharedSession.loadNote(url,
completionHandler: { text, error -> Void in
if let theText = text {
// 显示笔记文本
self.noteContentLabel.setText(theText)
}
})
}
}
7. 处理错误情况
在
awakeWithContext
方法中添加错误处理代码:
override func awake(withContext context: Any?) {
// 希望接收到指向 iPhone 上笔记的 NSURL
if let url = context as? URL {
// 先清空标签
self.noteContentLabel.setText(nil)
SessionManager.sharedSession.loadNote(url,
completionHandler: { text, error -> Void in
if let theError = error {
// 显示错误提示
let closeAction = WKAlertAction(title: "Close",
style: WKAlertActionStyle.default,
handler: { () -> Void in
self.pop()
})
self.presentAlert(withTitle: "Error loading note",
message: theError.localizedDescription,
preferredStyle: WKAlertControllerStyle.alert,
actions: [closeAction])
return
}
if let theText = text {
// 显示笔记文本
self.noteContentLabel.setText(theText)
}
})
}
}
运行应用,若显示笔记内容出错,会弹出警告框。
8. 创建新笔记功能
通过菜单项实现 Apple Watch 上创建新笔记的功能,用户用力按压笔记列表屏幕,会出现创建新笔记的按钮,点击后可听写文本,完成后
NoteListInterfaceController
会将文本发送到 iPhone 创建笔记。
8.1 创建菜单项
-
打开
Interface.storyboard文件。 -
在对象库搜索
Menu并拖到NoteListInterfaceController上。 -
选中默认菜单项,打开
Attributes Inspector。 -
将其图像设置为
Add,标题设置为Create Note。 -
按住
Control键,从菜单项拖到NoteListInterfaceController,创建名为createNote的新动作。
8.2 实现创建笔记方法
在
createNote
方法中添加以下代码:
@IBAction func createNote() {
let suggestions = [
"Awesome note!",
"What a great test note!",
"I love purchasing and reading books from O'Reilly Media!"
]
self.presentTextInputController(withSuggestions: suggestions,
allowedInputMode: WKTextInputMode.plain) {
(results) -> Void in
if let text = results?.first as? String {
SessionManager
.sharedSession
.createNote(text, completionHandler: { notes, error in
self.updateListWithNotes(notes)
})
}
}
}
运行应用,用力按压笔记列表开始听写,完成后会创建新笔记。
9. 添加手表与 iPhone 之间的接力功能
添加从 Apple Watch 到 iPhone 的接力功能,用户在手表上查看笔记时打开 iPhone,屏幕左下角会出现接力图标,向上滑动图标,文档会在 iOS 应用中打开。
9.1 添加接力相关代码
-
打开
DocumentCommon.swift文件,添加以下代码:
let WatchHandoffDocumentURL = "watch_document_url_key"
-
打开
DocumentListViewController.swift,在restoreUserActivityState方法中添加代码:
override func restoreUserActivityState(_ activity: NSUserActivity) {
// 被告知打开文档
if let url = activity.userInfo?[NSUserActivityDocumentURLKey] as? URL {
// 打开文档
self.performSegue(withIdentifier: "ShowDocument", sender: url)
}
// 来自手表的接力
if let urlString = activity
.userInfo?[WatchHandoffDocumentURL] as? String,
let url = URL(string: urlString) {
// 打开文档
self.performSegue(withIdentifier: "ShowDocument", sender: url)
}
// 来自搜索结果
if let searchableItemIdentifier = activity
.userInfo?[CSSearchableItemActivityIdentifier] as? String,
let url = URL(string: searchableItemIdentifier) {
// 打开文档
self.performSegue(withIdentifier: "ShowDocument", sender: url)
}
}
9.2 广播用户活动
在
NoteInterfaceController.swift
的
awakeWithContext
方法中添加代码:
override func awake(withContext context: Any?) {
// 希望接收到指向 iPhone 上笔记的 NSURL
if let url = context as? URL {
// 先清空标签
self.noteContentLabel.setText(nil)
let activityInfo = [WatchHandoffDocumentURL: url.absoluteString]
// 注意此字符串需与 iOS 和 Mac 应用 Info.plist 中定义的活动类型相同
updateUserActivity("au.com.secretlab.Notes.editing",
userInfo: activityInfo, webpageURL: nil)
SessionManager.sharedSession.loadNote(url,
completionHandler: { text, error -> Void in
if let theError = error {
// 显示错误提示
let closeAction = WKAlertAction(title: "Close",
style: WKAlertActionStyle.default,
handler: { () -> Void in
self.pop()
})
self.presentAlert(withTitle: "Error loading note",
message: theError.localizedDescription,
preferredStyle: WKAlertControllerStyle.alert,
actions: [closeAction])
return
}
if let theText = text {
// 显示笔记文本
self.noteContentLabel.setText(theText)
}
})
}
}
在 Apple Watch 上运行应用并打开笔记,打开 iPhone 就能看到接力图标,滑动图标文档会在 iOS 应用中打开。
以下是部分操作流程的 mermaid 流程图:
graph LR
A[创建新笔记] --> B[用力按压笔记列表屏幕]
B --> C[出现创建笔记按钮]
C --> D[点击按钮听写文本]
D --> E[NoteListInterfaceController 发送文本到 iPhone]
E --> F[创建新笔记]
打造 Apple Watch 笔记应用:功能实现与交互优化
10. 功能总结与关键操作回顾
为了更清晰地展示整个笔记应用的功能和操作流程,我们对前面的内容进行总结,以下是关键功能及对应操作步骤的表格:
| 功能 | 操作步骤 |
| — | — |
| 创建新笔记 | 1. 用力按压笔记列表屏幕;2. 点击“Create Note”按钮;3. 选择建议文本或听写内容;4. 完成后自动创建新笔记并更新列表 |
| 显示笔记列表 | 应用启动时自动请求 iPhone 上的笔记列表并显示 |
| 查看笔记内容 | 1. 在笔记列表中点击某条笔记;2. 通过 segue 过渡到新界面;3. 自动请求并显示笔记内容 |
| 接力功能 | 1. 在 Apple Watch 上打开笔记;2. 打开 iPhone,屏幕左下角出现接力图标;3. 向上滑动图标,在 iOS 应用中打开文档 |
11. 代码结构与逻辑梳理
整个应用的代码结构和逻辑可以通过以下 mermaid 流程图来梳理:
graph LR
A[App 启动] --> B[设置 WCSession]
B --> C[显示笔记列表界面]
C --> D[请求笔记列表]
D --> E[更新笔记列表]
C --> F[用户点击笔记]
F --> G[传递笔记 URL]
G --> H[显示笔记内容界面]
H --> I[请求笔记内容]
I --> J[显示笔记内容]
C --> K[用户用力按压屏幕]
K --> L[显示创建笔记菜单]
L --> M[输入笔记内容]
M --> N[发送内容到 iPhone 创建笔记]
N --> E
H --> O[接力功能触发]
O --> P[传递文档 URL]
P --> Q[在 iOS 应用中打开文档]
12. 常见问题与解决方案
在开发和使用过程中,可能会遇到一些常见问题,以下是部分问题及对应的解决方案:
| 问题 | 解决方案 |
| — | — |
| 接力功能在模拟器上无法使用 | 接力功能仅在物理设备上可用,需要在实际的 Apple Watch 和 iPhone 上进行测试 |
| 听写功能在模拟器上不工作 | 若要在模拟器上测试,需传递建议文本列表,而不是使用 nil,否则会直接进入听写模式,而模拟器不支持听写 |
| 显示笔记内容出错 | 在
awakeWithContext
方法中添加了错误处理代码,若出现错误会弹出警告框,可根据警告信息排查问题 |
13. 未来功能拓展方向
基于现有的笔记应用,我们可以考虑以下未来功能拓展方向:
1.
笔记编辑功能
:允许用户在 Apple Watch 上直接编辑笔记内容,而不仅仅是查看和创建。
2.
笔记分类与标签
:为笔记添加分类和标签,方便用户对笔记进行管理和查找。
3.
同步状态显示
:在界面上显示笔记的同步状态,让用户清楚知道哪些笔记已经同步到 iPhone。
4.
分享功能
:支持将笔记分享到其他应用或平台,如邮件、短信等。
14. 总结
通过一系列的操作和代码实现,我们成功打造了一个功能较为完善的 Apple Watch 笔记应用。从实现设备间的通信,到构建用户界面,再到添加各种功能如创建笔记、显示内容、接力等,每一步都有明确的操作步骤和代码示例。同时,我们也对可能遇到的问题提供了解决方案,并展望了未来的功能拓展方向。希望这些内容能帮助开发者更好地理解和开发 Apple Watch 应用。
在实际开发过程中,开发者可以根据自己的需求对代码和功能进行调整和优化,不断提升应用的性能和用户体验。相信通过不断的学习和实践,能够开发出更加优秀的 Apple Watch 应用。
超级会员免费看
7

被折叠的 条评论
为什么被折叠?



