一、3D Touch 簡介
在iOS 9中,新 iPhone 將第三維度添加到了用戶界面。
- 用戶現在可以用力摁下主屏按鈕來快速調出應用提供的功能菜單。
- 在應用中,用戶現在可以用力摁下視圖以查看更多內容的預覽并且快速訪問一些功能。
本文主要講解 3D Touch 各種場景下的開發方法,開發主屏幕應用 icon 上的快捷選項標簽(Home Screen Quick Actions),靜態設置 UIApplicationShortcutItem ,動態添加 UIApplicationShortcutItem,以及 Peek 和 Pop 的實現。
二、Home Screen Quick Actions
添加Home Screen Quick Actions有兩種方式:
1、通過Plist文件靜態設置;
2、通過代碼動態添加。
兩種方法的區別在于:通過Plist設置無需運行程序,也就是說在下載App后,不需要打開應用,就可以即可喚出Home Screen Quick Actions;而通過代碼動態添加的,必須在第一次下載后打開App,才能出現Home Screen Quick Actions。
1. 通過Plist文件靜態設置
在應用的 Info.plist 文件中添加UIApplicationShortcutItems
數組。
數組中添加字典,如下圖所示:
其中,字典的Key有以下選項:
名稱 | 說明 | 是否必須 |
---|---|---|
UIApplicationShortcutItemTitle | 標簽的標題 | 必填 |
UIApplicationShortcutItemType | 標簽的唯一標識 | 必填 |
UIApplicationShortcutItemIconType | 使用系統圖標的類型,如搜索、定位、home等 | 可選 |
UIApplicationShortcutItemIconFile | 使用項目中的圖片作為標簽圖標 | 可選 |
UIApplicationShortcutItemSubtitle | 標簽副標題 | 可選 |
UIApplicationShortcutItemUserInfo | 字典信息,如傳值使用 | 可選 |
第一個圖片使用系統自帶的,第二個是使用Assets.xcassets
文件夾中的圖片,當完成設置后,效果如下:
2. 通過代碼動態添加
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let item1 = UIApplicationShortcutItem(type: "2", localizedTitle: "code add item1", localizedSubtitle: "code add subtitle", icon: UIApplicationShortcutIcon(templateImageName: "shortcut_scorecard"), userInfo: nil)
let item2 = UIApplicationShortcutItem(type: "3", localizedTitle: "code add item2", localizedSubtitle: nil, icon: UIApplicationShortcutIcon(type: .add), userInfo: nil)
application.shortcutItems = [item1, item2]
return true
}
效果如下:
注意:目前Home Screen Quick Actions最多只能添加4個。
無論用哪種方式添加,當點擊item后,都會調用
AppDelegate
中的application(_:performActionFor:completionHandler:)
方法:
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
print(shortcutItem.type) // 通過type來判斷是點擊了哪一個按鈕
}
三、Peek and Pop(預覽與跳轉)
- Peek:輕按,屏幕視圖就會過渡到Peek,一個你設置的用來展示更多內容的視圖-就像Mail app做的一樣。如果用戶這時結束了觸碰,Peek就會消失并且應用回到交互開始之前的狀態。當你用力按下屏幕按到一定程度時,系統會彈出一個預覽視圖,這個過程就稱之為Peek。
- Pop:或者這個時候,用戶可以在peek界面上更用力按下來跳轉到使用peek呈現的視圖,這個過渡動畫會使用系統提供的pop過渡。pop出來的視圖會填滿你應用的根視圖并顯示一個返航按鈕可以回到交互開始的地方。再用力按下去就會展開到預覽視圖的控制器,這過程就是Pop。
實現步驟:
- 注冊預覽代理
// Registers a view controller to participate with 3D Touch preview (peek) and commit (pop).
@available(iOS 9.0, *)
// 第一個參數:代理
// 第二個參數:哪個view執行Peek
open func registerForPreviewing(with delegate: UIViewControllerPreviewingDelegate, sourceView: UIView) -> UIViewControllerPreviewing
- 遵守協議:
UIViewControllerPreviewingDelegate
- 實現協議方法
// If you return nil, a preview presentation will not be performed
@available(iOS 9.0, *)
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
@available(iOS 9.0, *)
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController)
接下來用一個tableView的例子??來說明,實現以下效果:
代碼如下:
import UIKit
class ViewController: UIViewController {
fileprivate lazy var array = [String]()
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...20 { array.append("第\(i)行") }
// 注冊Cell
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
// 判斷系統版本,必須iOS 9及以上,同時檢測是否支持觸摸力度識別
if #available(iOS 9.0, *), traitCollection.forceTouchCapability == .available {
// 注冊預覽代理,self監聽,tableview執行Peek
registerForPreviewing(with: self, sourceView: tableView)
}
}
}
// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
cell.textLabel?.text = array[indexPath.row]
return cell
}
}
// MARK: - UIViewControllerPreviewingDelegate
@available(iOS 9.0, *)
extension ViewController: UIViewControllerPreviewingDelegate {
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
// 模態彈出需要展現的控制器
showDetailViewController(viewControllerToCommit, sender: nil)
// 通過導航欄push需要展現的控制器
// show(viewControllerToCommit, sender: nil)
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
// 獲取indexPath和cell
guard let indexPath = tableView.indexPathForRow(at: location), let cell = tableView.cellForRow(at: indexPath) else { return nil }
// 設置Peek視圖突出顯示的frame
previewingContext.sourceRect = cell.frame
let vc = DetalViewController()
// 返回需要彈出的控制權
return vc
}
}
在實際開發中,你可能會用到 UIView中的坐標轉換 的幾個方法(可跳過不看):
// 將像素point由point所在視圖轉換到目標視圖view中,返回在目標視圖view中的像素值
open func convert(_ point: CGPoint, to view: UIView?) -> CGPoint
// 例如:point2 = view1.convert(point1, toView: view2):把point1從view1的坐標系中,轉換到view2的坐標系中
// 將像素point從view中轉換到當前視圖中,返回在當前視圖中的像素值
open func convert(_ point: CGPoint, from view: UIView?) -> CGPoint
// 例如:point2 = view1.convert(point1, from: view2):把point1從view2的坐標系中,轉換到view1的坐標系中
// 將rect由rect所在視圖轉換到目標視圖view中,返回在目標視圖view中的rect
open func convert(_ rect: CGRect, to view: UIView?) -> CGRect
// 例如:rect2 = view1.convert(rect1, toView: view2):把rect1從view1的坐標系中,轉換到view2的坐標系中
// 將rect從view中轉換到當前視圖中,返回在當前視圖中的rect
open func convert(_ rect: CGRect, from view: UIView?) -> CGRect
// 例如:rect2 = view1.convert(rect1, toView: view2):把rect1從view2的坐標系中,轉換到view1的坐標系中
四、Peek快速選項
如果用戶一直保持觸摸,可以向上滑動Peek視圖,系統會展示出你預先設置和peek關聯的peek快速選項。
每一項peek快速選項都是你應用中的深度鏈接。當peek快速選項出現后,用戶可以停止觸摸而且peek會停留在屏幕中。用戶可點擊一個快速選項,喚出相關鏈接。
在本例中,實現以上效果,只需要在
DetalViewController
中添加以下代碼即可:
import UIKit
class DetalViewController: UIViewController {
@available(iOS 9.0, *)
lazy var previewActions: [UIPreviewActionItem] = {
let a = UIPreviewAction(title: "這是一個default按鈕", style: .default, handler: { (action, vc) in
// 這里實現點擊按鈕事件處理
})
let b = UIPreviewAction(title: "這是一個destructive按鈕", style: .destructive, handler: { (action, vc) in
// 這里實現點擊按鈕事件處理
})
return [a, b]
}()
@available(iOS 9.0, *)
override var previewActionItems: [UIPreviewActionItem] {
return previewActions
}
}
最后注意:以上全部功能必須要求為 iPhone 6s 及以上機型,并且是 iOS 9 及以上,才有效果,模擬器可以看到效果,不需要安裝任何插件,但必須要有觸摸盤才行,在觸摸盤上的點擊就是3D Touch。