在支持3D Touch的设备上,用户可以通过对触摸屏施加不同程度的压力来访问其他功能,应用程序可以通过显示上下文菜单(或支持Peek和Pop)来响应,以显示一些可供用户操作的选项或者行为。
在运行iOS 13及以后版本的设备上,人们可以使用touch和hold手势来打开上下文菜单,而不管设备是否支持3D touch。在3D触摸设备上,手势可以更快地显示上下文菜单,对特性的独立访问。
3D Touch主要分为两种:
本文所有示例及代码全部基于xcode12,iOS13.
当用户长按APP图标或者施加一定压力的时候,程序会在适当的位置展示出一个菜单选项列表。当用户选择一个快速动作时,APP启动,程序的应用委托对象接收到快速动作消息。
配置一个主屏幕快捷操作,可分为静态和动态两种方式。
这种方式主要是在项目的Info.plist文件中添加相关的属性。
参考如下:
或者像下面这样配置,效果都一样:
UIApplicationShortcutItems
UIApplicationShortcutItemIconFile
open-favorites
UIApplicationShortcutItemTitle
Favorites
UIApplicationShortcutItemType
com.mycompany.myapp.openfavorites
UIApplicationShortcutItemUserInfo
key1
value1
UIApplicationShortcutItemIconType
UIApplicationShortcutIconTypeCompose
UIApplicationShortcutItemTitle
New Message
UIApplicationShortcutItemType
com.mycompany.myapp.newmessage
UIApplicationShortcutItemUserInfo
key2
value2
下面针对上面配置的key值来了解一下:
Key |
配置要求 | 描述 |
---|---|---|
|
必填 | 快捷操作项的唯一标识,用于区别其他快捷操作项。 |
|
必填 | 快捷操作项的主标题。 如果主标题能够一行显示的话,就一行显示。如果太长了一行显示不小的话,如果没有配置副标题,那么主标题显示两行。 |
|
选填 | 快捷操作项的副标题,显示在主标题的下面。 如果制定了副标题,但是主标题又太长了,那么主标题只显示一行,多余的打点。 |
|
选填 | 配置系统提供的快捷操作项的图标。 |
|
选填 | 配置自定义的快捷操作项的图标,如果配置了这个key,那么系统将会忽略
|
|
选填 | 快捷操作项的附加信息,字典类型。 |
注明:这些key用在iOS9及以上且支持3D Touch的设备上。
下表为系统提供的快捷操作项的图标:
这种方式主要通过代码的形式把UIApplicationShortcutItem对象数组传递给UIApplication单例对象。
UIApplicationShortcutItem就是屏幕上弹出的列表中列表项对应的数据模型,下面看一下这个类的初始化方法以及相关属性:
方法或属性 | 描述 |
---|---|
init(type: String, localizedTitle: String) |
初始化方法 |
init(type: String, localizedTitle: String, localizedSubtitle: String?, icon: UIApplicationShortcutIcon?, userInfo: [String : NSSecureCoding]?) |
初始化方法 |
var localizedTitle: String |
主标题 |
var localizedSubtitle: String? |
副标题 |
var type: String |
唯一标识 |
var icon: UIApplicationShortcutIcon? |
图标 |
var userInfo: [String : NSSecureCoding]? |
附加信息 |
如果同时使用静态和动态的方法添加,其添加的先后顺序是:先添加静态UIApplicationShortcutItem对象,如果静态UIApplicationShortcutItem对象不足4个,则继续添加动态UIApplicationShortcutItem对象。官方文档提及到最多只能添加4个UIApplicationShortcutItem对象。
下面看一下示例代码:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let dynamicIcon1 = UIApplicationShortcutIcon(systemImageName: "play")
let dynamicItem1 = UIApplicationShortcutItem(type: "play", localizedTitle: "播放", localizedSubtitle: "播放喜欢的内容", icon: dynamicIcon1, userInfo: nil)
let dynamicIcon2 = UIApplicationShortcutIcon(systemImageName: "message")
let dynamicItem2 = UIApplicationShortcutItem(type: "message", localizedTitle: "消息", localizedSubtitle: "发送消息", icon: dynamicIcon2, userInfo: nil)
let dynamicIcon3 = UIApplicationShortcutIcon(systemImageName: "favorite")
let dynamicItem3 = UIApplicationShortcutItem(type: "favorite", localizedTitle: "喜欢", localizedSubtitle: "喜欢的节目", icon: dynamicIcon3, userInfo: nil)
UIApplication.shared.shortcutItems = [dynamicItem1, dynamicItem2, dynamicItem3]
return true
}
上面代码动态添加了3个UIApplicationShortcutItem对象,另外还配置了两个静态UIApplicationShortcutItem对象,如下图:
最终运行结果如下,动态创建的第三个UIApplicationShortcutItem对象,没有显示出来。
当点击对应的快捷操作项后,APP被唤醒或者启动.
1. 当APP没有运行起来的时候,点击后APP启动,并且通过scene(_:willConnectTo:options:)
方法中的connectionOptions参数携带shortcut对象信息。这个方法中先保存shortcut对象信息,带APP完全启动后,再根据shortcut对象信息执行后续操作。
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
/** Process the quick action if the user selected one to launch the app.
Grab a reference to the shortcutItem to use in the scene.
*/
if let shortcutItem = connectionOptions.shortcutItem {
// Save it off for later when we become active.
savedShortCutItem = shortcutItem
}
}
2. 当APP已经运行起来(包括压在后台),点击后APP唤醒,并且调用 windowScene(_:performActionFor:completionHandler:)方法传递
shortcut对象信息。
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
print(shortcutItem.localizedTitle)
}
Peek和Pop是应用内的一种全新交互模式,当用户不断增加力量在控件上按压,会依次进入四个阶段:
比如iPhone手机的信息APP以及微信,都有这个功能。
下面看一个Demo,Demo中会从一个tableview界面,按压cell调入到detail界面,其经过如下图:
上面四个图正好对应了四个阶段。
如要想cell用力按压后有预览效果,首先需要向cell注册3D功能,代码如下:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
cell?.textLabel?.text = "这是第\(indexPath.row)行"
// 判断是否支持3D Touch功能。
if traitCollection.forceTouchCapability == .available {
self.registerForPreviewing(with: self, sourceView: cell!)
}
return cell!
}
注册完之后,需要实现其协议方法:
@available(iOS 9.0, *)
public protocol UIViewControllerPreviewingDelegate : NSObjectProtocol {
// 该方法返回一个可供预览的视图,如果返回nil,则无预览图。
@available(iOS, introduced: 9.0, deprecated: 13.0, renamed: "UIContextMenuInteraction")
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
// 实现该方法,则会跳入到预览图控制器界面。
@available(iOS, introduced: 9.0, deprecated: 13.0, renamed: "UIContextMenuInteraction")
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController)
}
Demo中两个协议方法现实如下:
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
// 获取按压的cell
guard let cell = previewingContext.sourceView as? UITableViewCell else {
return nil
}
// 获取cell的indexPath
guard let indexPath = tableView.indexPath(for: cell) else {
return nil
}
// sourceRect边界外部虚化。
previewingContext.sourceRect = cell.frame
let detailVC = DetailViewController(nibName: "DetailViewController", bundle: nil)
detailVC.number = indexPath.row
detailVC.title = "\(indexPath.row)"
return detailVC
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
show(viewControllerToCommit, sender: self)
}
实现上述代码即可实现1、2、4个阶段的功能。
如果要实现预览界面上滑显示快捷项列表,则需要在目标控制器复写previewActionItems属性。
下面在目标控制器(DetailViewController)界面复写previewActionItems属性。
override var previewActionItems: [UIPreviewActionItem] {
let action1 = UIPreviewAction(title: "喜欢", style: .default) { (action, controller) in
}
let action2 = UIPreviewAction(title: "收藏", style: .default) { (action, controller) in
}
let action3 = UIPreviewAction(title: "删除", style: .default) { (action, controller) in
}
return [action1, action2, action3]
}
以上就完成了3D Touch功能,当然此功能不限于UITableView。在iOS13之后,上面的相关方法以及协议将会废弃,由UIContextMenuInteraction取代,关于UIContextMenuInteraction,在后续博文中将继续介绍,敬请关注!
参考文档:
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/index.html#//apple_ref/doc/uid/TP40016543-CH1-SW1
本篇文章出自https://blog.csdn.net/guoyongming925的博客,如需转载,请标明出处。