3D Touch 功能的实现与应用
1. 检测压力
若要检测用户按压屏幕的压力,需先确保设备支持 3D Touch。可在以下环境中模拟 3D Touch:
- 在配备触摸板的笔记本 Macintosh 或带有 Magic Trackpad 的台式 Macintosh 上运行模拟器。
- 通过 USB 线将 iPhone 6s 或更高版本连接到 Macintosh 上。
检测 3D Touch 压力的两个属性为 “force” 和 “maximumPossibleForce”。“force” 属性测量当前压力值,“maximumPossibleForce” 属性定义 iOS 可识别的最大压力。
以下是检测压力的实现步骤:
1. 在 Main.storyboard 文件中拖放一个 UILabel。
2. 打开 Assistant Editor,从 UILabel 按住 Control 键拖动到 ViewController.swift 文件,创建一个名为 forceLabel 的 IBOutlet:
@IBOutlet var forceLabel: UILabel!
- 修改 touchesMoved 函数:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
if #available(iOS 9.0, *) {
if traitCollection.forceTouchCapability == UIForceTouchCapability.available {
let force = touch.force/touch.maximumPossibleForce
forceLabel.text = "\(force * 100)% force"
} else {
print ("3D Touch not available")
}
} else {
print ("Need iOS 9 or higher")
}
}
}
此修改后的代码从 touch.force 属性获取屏幕压力,将其除以 maximumPossibleForce 属性,最后在应用界面的标签中以百分比形式显示该值。运行应用时,可按压 Macintosh 触控板或 iPhone 屏幕,查看按压力度。
2. 创建主屏幕快速操作
快速操作让用户可通过不同选项打开应用,为应用常用功能提供快捷方式。例如,在主屏幕上对 Safari 图标使用快速操作,可选择打开新标签、隐私标签、阅读列表或书签列表。
创建快速操作分为两部分:
2.1 定义快速操作菜单
在 info.plist 文件的字典中定义多个字符串,创建最多四个快速操作菜单。每个快速操作可显示标题、副标题和图标。具体操作如下:
1. 点击 Navigator 面板中的 Info.plist 文件,显示应用的信息属性列表。
2. 点击属性列表中任意键项右侧的上下箭头图标,出现 “+” 和 “-” 图标。
3. 点击 “+” 键创建一个新的属性列表项,命名为 UIApplicationShortcutItems,确保其类型为数组。
4. 重复上述步骤创建两个项目,编号为 Item 0 和 Item 1,创建两个主屏幕快速操作。
5. 在每个项目下创建三个额外的行,分别命名为:
- UIApplicationShortcutItemTitle:定义快速操作快捷方式的标题。
- UIApplicationShortcutItemSubtitle:定义快速操作快捷方式的副标题,以较小字体显示在标题下方(可选)。
- UIApplicationShortcutItemType:定义创建快速操作快捷菜单所需的字符串。
以下是创建两个快速操作快捷方式的示例:
| Key | Type | Value |
| — | — | — |
| UIApplicationShortcutItems | Array | (2 items) |
| Item 0 | Dictionary | (3 items) |
| UIApplicationShortcutItemTitle | String | View |
| UIApplicationShortcutItemSubtitle | String | View favorite items |
| UIApplicationShortcutItemType | String | $(PRODUCT_BUNDLE_IDENTIFIER).First |
| Item 1 | Dictionary | (3 items) |
| UIApplicationShortcutItemTitle | String | Share |
| UIApplicationShortcutItemSubtitle | String | Share items with friends |
| UIApplicationShortcutItemType | String | $(PRODUCT_BUNDLE_IDENTIFIER).Second |
2.2 编写 Swift 代码处理快速操作
在 AppDelegate.swift 文件中编写 Swift 代码处理每个快速操作。首先,创建一个枚举来标识每个快速操作项:
enum MenuItems: String {
case First
case Second
init?(fullType: String) {
guard let last = fullType.components(separatedBy: ".").last else { return nil }
self.init(rawValue: last)
}
// MARK: Properties
var type: String {
return Bundle.main.bundleIdentifier! + ".\(self.rawValue)"
}
}
然后,在 AppDelegate.swift 文件中创建一个 UIApplicationShortcutItem 类型的变量:
var launchedShortcutItem: UIApplicationShortcutItem?
接着,编写两个应用函数:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {
launchedShortcutItem = shortcutItem
}
return true
}
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
completionHandler(handleShortCutItem(shortcutItem))
}
最后,编写 handleShortCutItem 函数:
func handleShortCutItem(_ shortcutItem: UIApplicationShortcutItem) -> Bool {
var handled = false
guard MenuItems(fullType: shortcutItem.type) != nil else {
return false
}
guard let shortCutType = shortcutItem.type as String? else {
return false
}
switch (shortCutType) {
case MenuItems.First.type:
print ("View favorites")
handled = true
case MenuItems.Second.type:
print ("Share")
handled = true
default:
break
}
let alertController = UIAlertController(title: "Shortcut Chosen", message: "\"\(shortcutItem.localizedTitle)\"", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(okAction)
window!.rootViewController?.present(alertController, animated: true, completion: nil)
return handled
}
3. 添加动态主屏幕快速操作
之前定义的快速操作为静态操作,始终显示。动态快速操作可在应用运行后通过 Swift 代码创建,使快速操作菜单根据用户当前操作显示不同选项。
注意,快速操作最多只能有四个,如一个静态快速操作和三个动态快速操作,或四个静态快速操作和零个动态快速操作。
添加动态快速操作的步骤如下:
1. 修改枚举,为每个要添加的动态快速操作添加一个枚举项:
enum MenuItems: String {
case First
case Second
case Third
case Fourth
init?(fullType: String) {
guard let last = fullType.components(separatedBy: ".").last else { return nil }
self.init(rawValue: last)
}
// MARK: Properties
var type: String {
return Bundle.main.bundleIdentifier! + ".\(self.rawValue)"
}
}
-
修改 existing application didFinishLaunchingWithOptions 函数:
- 定义每个动态快速操作:
let shortcut3 = UIMutableApplicationShortcutItem(type: MenuItems.Third.type, localizedTitle: "Play", localizedSubtitle: "Play audio", icon: UIApplicationShortcutIcon(type: .play))
let shortcut4 = UIMutableApplicationShortcutItem(type: MenuItems.Fourth.type, localizedTitle: "Add", localizedSubtitle: "Add an item", icon: UIApplicationShortcutIcon(type: .add))
- 将动态快速操作添加到 shortcutItems 数组:
application.shortcutItems = [shortcut3, shortcut4]
完整的 AppDelegate.swift 文件如下:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var launchedShortcutItem: UIApplicationShortcutItem?
enum MenuItems: String {
case First
case Second
case Third
case Fourth
init?(fullType: String) {
guard let last = fullType.components(separatedBy: ".").last else { return nil }
self.init(rawValue: last)
}
// MARK: Properties
var type: String {
return Bundle.main.bundleIdentifier! + ".\(self.rawValue)"
}
}
func handleShortCutItem(_ shortcutItem: UIApplicationShortcutItem) -> Bool {
var handled = false
guard MenuItems(fullType: shortcutItem.type) != nil else {
return false
}
guard let shortCutType = shortcutItem.type as String? else {
return false
}
switch (shortCutType) {
case MenuItems.First.type:
print ("View favorites")
handled = true
case MenuItems.Second.type:
print ("Share")
handled = true
default:
break
}
let alertController = UIAlertController(title: "Shortcut Chosen", message: "\"\(shortcutItem.localizedTitle)\"", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(okAction)
window!.rootViewController?.present(alertController, animated: true, completion: nil)
return handled
}
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
completionHandler(handleShortCutItem(shortcutItem))
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {
launchedShortcutItem = shortcutItem
}
if let shortcutItems = application.shortcutItems, shortcutItems.isEmpty {
let shortcut3 = UIMutableApplicationShortcutItem(type: MenuItems.Third.type, localizedTitle: "Play", localizedSubtitle: "Play audio", icon: UIApplicationShortcutIcon(type: .play))
let shortcut4 = UIMutableApplicationShortcutItem(type: MenuItems.Fourth.type, localizedTitle: "Add", localizedSubtitle: "Add an item", icon: UIApplicationShortcutIcon(type: .add))
application.shortcutItems = [shortcut3, shortcut4]
}
return true
}
}
通过修改 shortcutItems 数组,应用可动态更改快速操作菜单中的快速操作,如添加或删除项目,但总数不能超过四个。
4. 添加窥视、弹出和预览功能
3D Touch 的最后一个用途是为项目添加窥视功能。窥视让用户按压项目以聚焦该项目,按住手指会弹出该项目的小视图,预览则可查看执行任务的菜单项。
4.1 创建项目和界面
创建一个新的 Single View App iOS 项目,命名为 3D PeekPop。点击 Main.storyboard 文件,在视图中间放置一个 UIButton,设置描述性标题,如 “Touch Me to Peek”,并更改背景颜色。最后选择 “Editor ➤ Resolve Auto Layout Issues ➤ Reset to Suggested Constraints” 创建简单用户界面。
4.2 实现窥视、弹出和预览功能
- 打开 Assistant Editor,从按钮按住 Control 键拖动创建一个名为 peekButton 的 IBOutlet。
- 让视图控制器采用 UIViewControllerPreviewingDelegate 协议:
class ViewController: UIViewController, UIViewControllerPreviewingDelegate {
@IBOutlet var peekButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
if traitCollection.forceTouchCapability == .available {
registerForPreviewing(with: self, sourceView: view)
}
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let showMyView = storyboard?.instantiateViewController(withIdentifier: "PeekVC"), peekButton.frame.contains(location) else {
return nil
}
showMyView.preferredContentSize = CGSize(width: 0.0, height: 300.0)
return showMyView
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
show(viewControllerToCommit, sender: self)
}
}
4.3 创建第二个视图和代码文件
- 在 Navigator 面板中点击 Main.storyboard 文件,拖放一个 View Controller 到现有视图旁边。
- 在新视图顶部附近拖动一个 UILabel,调整大小,设置标题为 “Touch Me to Peek”,并更改背景颜色。
- 点击第二个视图顶部的黄色圆圈,选择 “View ➤ Utilities ➤ Show Identity Inspector”,在 Storyboard ID 中输入 “PeekVC”。
- 创建一个名为 ViewControllerPeek 的 Cocoa Touch Class 文件,确保它是 UIViewController 的子类并使用 Swift 语言。
- 在 Identity Inspector 面板中,点击 Class 列表框,选择 ViewControllerPeek,将视图与 ViewControllerPeek.swift 文件连接。
4.4 定义预览菜单项
在 ViewControllerPeek.swift 文件中定义预览菜单项:
import UIKit
class ViewControllerPeek: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override var previewActionItems : [UIPreviewActionItem] {
let defaultAction = UIPreviewAction(title: "Default style", style: .default) { (action, viewController) -> Void in
print("Default")
}
let selectAction = UIPreviewAction(title: "Selected style", style: .selected) { (action, viewController) -> Void in
print("Selected")
}
let destructiveAction = UIPreviewAction(title: "Destructive style", style: .destructive) { (action, viewController) -> Void in
print("Destructive")
}
return [defaultAction, selectAction, destructiveAction]
}
}
通过以上步骤,可实现 3D Touch 的各种功能,为应用增添更多交互性和便捷性。
5. 3D Touch 功能实现流程总结
为了更清晰地展示 3D Touch 各项功能的实现步骤,下面通过 mermaid 流程图和表格的形式进行总结。
5.1 检测压力功能流程图
graph LR
A[确保设备支持 3D Touch] --> B[模拟运行环境选择]
B --> |笔记本 Mac 或台式 Mac 模拟器| C[在模拟器运行]
B --> |iPhone 6s 及以上连接 Mac| D[在 iPhone 运行]
C --> E[在 Main.storyboard 拖放 UILabel]
D --> E
E --> F[创建 forceLabel 的 IBOutlet]
F --> G[修改 touchesMoved 函数]
G --> H[运行应用查看按压力度]
5.2 快速操作功能实现步骤表格
| 功能 | 步骤 | 操作内容 |
|---|---|---|
| 创建主屏幕快速操作 | 定义菜单 |
1. 点击 Info.plist 文件
2. 点击上下箭头,出现 “+” 和 “-” 图标 3. 点击 “+” 键创建 UIApplicationShortcutItems 数组 4. 创建两个项目 Item 0 和 Item 1 5. 在每个项目下创建三个额外行并命名 |
| 编写代码处理 |
1. 创建枚举标识快速操作项
2. 创建 UIApplicationShortcutItem 类型变量 3. 编写两个应用函数 4. 编写 handleShortCutItem 函数 | |
| 添加动态主屏幕快速操作 | 修改枚举 | 为每个动态快速操作添加枚举项 |
| 修改函数 |
1. 定义每个动态快速操作
2. 将动态快速操作添加到 shortcutItems 数组 |
5.3 窥视、弹出和预览功能流程图
graph LR
A[创建 3D PeekPop 项目] --> B[在 Main.storyboard 放置 UIButton]
B --> C[设置按钮标题和背景颜色]
C --> D[创建 peekButton 的 IBOutlet]
D --> E[视图控制器采用 UIViewControllerPreviewingDelegate 协议]
E --> F[创建第二个视图和代码文件]
F --> G[定义预览菜单项]
G --> H[实现窥视、弹出和预览功能]
6. 代码优化与注意事项
6.1 代码优化建议
- 检测压力功能 :可以添加更多的错误处理机制,例如当获取压力值失败时,给出更详细的错误提示,而不仅仅是打印信息。
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
if #available(iOS 9.0, *) {
if traitCollection.forceTouchCapability == UIForceTouchCapability.available {
do {
let force = try getForceValue(from: touch)
forceLabel.text = "\(force * 100)% force"
} catch {
print("获取压力值失败: \(error.localizedDescription)")
}
} else {
print ("3D Touch not available")
}
} else {
print ("Need iOS 9 or higher")
}
}
}
func getForceValue(from touch: UITouch) throws -> CGFloat {
guard touch.maximumPossibleForce > 0 else {
throw NSError(domain: "ForceError", code: 1, userInfo: [NSLocalizedDescriptionKey: "最大可能压力值为 0"])
}
return touch.force / touch.maximumPossibleForce
}
- 快速操作功能 :可以将一些重复的代码提取成函数,提高代码的复用性。例如将创建 UIAlertController 的代码提取成一个单独的函数。
func showAlertForShortcut(_ shortcutItem: UIApplicationShortcutItem) {
let alertController = UIAlertController(title: "Shortcut Chosen", message: "\"\(shortcutItem.localizedTitle)\"", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(okAction)
window!.rootViewController?.present(alertController, animated: true, completion: nil)
}
func handleShortCutItem(_ shortcutItem: UIApplicationShortcutItem) -> Bool {
var handled = false
guard MenuItems(fullType: shortcutItem.type) != nil else {
return false
}
guard let shortCutType = shortcutItem.type as String? else {
return false
}
switch (shortCutType) {
case MenuItems.First.type:
print ("View favorites")
handled = true
case MenuItems.Second.type:
print ("Share")
handled = true
default:
break
}
showAlertForShortcut(shortcutItem)
return handled
}
6.2 注意事项
- 拼写问题 :在定义快速操作的图标类型时,要特别注意拼写,包括大小写。Key 列使用 UIApplicationShortcutItemIconType,Value 列使用 UIApplicationShortcutIconType 后跟图标名称。
- 快速操作数量限制 :快速操作最多只能有四个,在添加或删除动态快速操作时,要确保总数不超过这个限制。
-
代码兼容性
:涉及到 iOS 版本的代码,如
#available(iOS 9.0, *),要确保应用的目标用户群体的 iOS 版本支持该功能。
通过以上的优化和注意事项,可以让 3D Touch 功能的实现更加稳定和高效,为用户带来更好的交互体验。
超级会员免费看
7778

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



