一、什么是3D Touch?
3D Touch是iPhone 6s推出的一种可以让你与手机进行互动的全新方式。除了轻点、轻扫、双指开合这些熟悉的 Multi‑Touch 手势之外,3D Touch 还带来 Peek 和 Pop,为 iPhone 的使用体验开拓出全新的维度。而且,当你使用 3D Touch 时,iPhone 将回以轻微的触感,让你不仅能够看到按下屏幕的操作效果,还能感觉得到。
二、3D Touch开发
1、Quick Actions(主屏幕快速选项)
用户通过按压屏幕上应用的icon,可以获得一系列的快捷选项,用户选取一个选项后,将会启动或加载应用,而应用的delegate会接受快捷选项的消息。
对于主屏幕快速选项我们有两种设置方式:静态,动态。
(1)、静态标签
静态标签是在项目的info.plist里面配置,用户安装应用后就可以使用,并且排在动态标签的前面。
配置info.plist文件
先添加了一个UIApplicationShortcutItems的数组,这个数组中添加的元素就是对应的静态标签,在每个标签中我们需要添加一些设置的键值:
必填项(下面两个键值是必须设置的):
UIApplicationShortcutItemType 这个键值设置一个快捷通道类型的字符串
UIApplicationShortcutItemTitle 这个键值设置标签的标题
选填项(下面这些键值不是必须设置的) :
UIApplicationShortcutItemSubtitle 设置标签的副标题
UIApplicationShortcutItemIconType 设置标签Icon类型(value在这个类中查看)
UIApplicationShortcutItemIconFile 设置标签的Icon文件(不想用系统的,自定义)
UIApplicationShortcutItemUserInfo 设置信息字典(用于传值)
效果如下:
(2)、动态标签
动态标签是在应用需要的时候,用代码添加的,相关的类有:
UIApplicationShortcutItem 创建3DTouch标签的类
UIMutableApplicationShortcutItem 创建可变3DTouch标签的类
UIApplicationShortcutIcon 创建标签中图片Icon的类
创建一个UIApplicationShortcutItem:
// 创建快捷方式的icon
let shortCutIcon: UIApplicationShortcutIcon = UIApplicationShortcutIcon(templateImageName: "icon_pass") // 自定义
//let shortCutIcon: UIApplicationShortcutIcon = UIApplicationShortcutIcon(type: .play) // 系统
// 创建快捷方式item
let shortchuItem: UIApplicationShortcutItem = UIApplicationShortcutItem(type: "Second", localizedTitle: "这是第二个", localizedSubtitle: "Second", icon: shortCutIcon, userInfo: nil)
// 添加
UIApplication.shared.shortcutItems = [shortchuItem]
效果如下:
修改某个shortchuItem
// 获取应用单前所有的动态标签标签,无法获取静态的
let application: UIApplication = UIApplication.shared
var shortcutItems: [UIApplicationShortcutItem]? = application.shortcutItems
// 修改应用当前的某个shortcutItems
let newShortcutItem: UIMutableApplicationShortcutItem = shortcutItems?[0].mutableCopy() as! UIMutableApplicationShortcutItem
newShortcutItem.localizedTitle = "第二个修改";
newShortcutItem.icon = UIApplicationShortcutIcon(type: .search)
// 重新添加
shortcutItems?[0] = newShortcutItem
application.shortcutItems = shortcutItems;
效果图如下:
(3)、响应标签行为
当我们点击标签进入应用时,我们要做一些操作,而我们可以看见在applocation中有这样一个方法:
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void)
当我们点击标签进入应用时,就会响应这个方法,在这个方法里面我们根据shortcutItem处理相应的操作。
而在App的入口方法:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if launchOptions?[.shortcutItem] != nil {
// return false
}
return true
}
我们可以判断launchOptions中shortcutItem(Object-C中为UIApplicationLaunchOptionsShortcutItemKey)这个键值是否为空,从而判断是否是从快捷标签进入应用的。有时候我们可能要处理这两种情况:
1、应用处于后台,点击标签进入应用
2、应用未运行,点击标签进入应用
如果这两种状态下的情况不一样,就需要在这里判断一下是不是上面两种中的情况2,如果是,则在App的入口方法中返回false,这样就不会走响应标签行为的那个方法。
标签最多可以创建4个,包括静态和动态。
2、Peek and Pop
1、检测3DTouch是否可用
// 检测3DTouch可不可用
func detection3DTouchIsAvailable() -> Bool {
return self.traitCollection.forceTouchCapability == .available ? true : false
}
如果可用,注册
self.registerForPreviewing(with: self, sourceView: view)
2、实现UIViewControllerPreviewingDelegate
// Peek
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
let previewingVC: UIViewController = UIViewController()
return previewingVC
}
// Pop
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
print(#function)
self.show(viewControllerToCommit, sender: self)
}
以上是整个view都响应3DTouch,你也可以指定某个视图。
在实际情况中我们可能遇到一个界面上有较多的地方需要响应3DTouch(像微信中的朋友圈)。这种情况我们不可能每个视图都去注册,而我的处理方式为(以tableview为例):
把tableview做为sourceView注册
self.registerForPreviewing(with: self, sourceView: tableView)
在peek方法中做处理:
(1)、判断location在那个cell上
open func indexPathForRow(at point: CGPoint) -> IndexPath?
(2)、转换坐标系(一直转换到你要处理的视图的父视图上)
public func convert(_ point: CGPoint, to coordinateSpace: UICoordinateSpace) -> CGPoint
(3)、判断转换后的点是否在某个视图上
public func contains(_ point: CGPoint) -> Bool
(4)、如果点有在某个视图上,做相应处理,否则返回nil
详见—— demo的PeekAndPopViewController
3、添加底部菜单,在对应的控制器里面重写
open var previewActionItems: [UIPreviewActionItem] { get }
示例如下:
// MARK: -- 添加底部菜单
override var previewActionItems: [UIPreviewActionItem] {
let action1: UIPreviewAction = UIPreviewAction(title: "action1", style: .default) { (action, viewController) in
// 处理操作
}
let action2: UIPreviewAction = UIPreviewAction(title: "action2", style: .destructive) { (action, viewController) in
}
let action3: UIPreviewAction = UIPreviewAction(title: "action3", style: .selected) { (action, viewController) in
}
return [action1,action2,action3]
}
4、Web View Peek and Pop
显示网页有三种方法:
(1)、openUrl离开应用进入safari打开网页
(2)、UIWebView或者WKWebView自定义视图在应用内打开网页
(3)、在iOS9.0后新增SFSafariViewController类,用于显示web网页。并通过SFSafariViewControllerDelegate的以下方法实现回到应用操作。
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
controller.dismiss(animated: true, completion: nil)
}
方法1不能实现3D Touch。
使用方法2实现3D Touch时,要设置webView属性 allowsLinkPreview 为true(默认是false)。
3、 UITouch Force Properties
在UITouch这个类中有force,maximumPossibleForce这两个属性,当按压屏幕越重时force就越大。
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch: UITouch = touches.first!
print("force = \(touch.force)\n,max = \(touch.maximumPossibleForce)\n,scale = \(touch.force/touch.maximumPossibleForce)")
let scale = 1.0-touch.force/touch.maximumPossibleForce
view.backgroundColor = UIColor(red: 1.0, green: scale, blue: scale, alpha: 1.0)
}
我的——demo
三、参考链接
[iOS]iOS9 3DTouch、ShortcutItem、Peek And Pop技术一览