一、3D Touch 簡(jiǎn)介
在iOS 9中奇瘦,新 iPhone 將第三維度添加到了用戶界面棘催。
- 用戶現(xiàn)在可以用力摁下主屏按鈕來快速調(diào)出應(yīng)用提供的功能菜單。
- 在應(yīng)用中耳标,用戶現(xiàn)在可以用力摁下視圖以查看更多內(nèi)容的預(yù)覽并且快速訪問一些功能巧鸭。
本文主要講解 3D Touch 各種場(chǎng)景下的開發(fā)方法,開發(fā)主屏幕應(yīng)用 icon 上的快捷選項(xiàng)標(biāo)簽(Home Screen Quick Actions)麻捻,靜態(tài)設(shè)置 UIApplicationShortcutItem 纲仍,動(dòng)態(tài)添加 UIApplicationShortcutItem呀袱,以及 Peek 和 Pop 的實(shí)現(xiàn)。
二郑叠、Home Screen Quick Actions
添加Home Screen Quick Actions有兩種方式:
1夜赵、通過Plist文件靜態(tài)設(shè)置;
2乡革、通過代碼動(dòng)態(tài)添加寇僧。
兩種方法的區(qū)別在于:通過Plist設(shè)置無需運(yùn)行程序,也就是說在下載App后沸版,不需要打開應(yīng)用嘁傀,就可以即可喚出Home Screen Quick Actions;而通過代碼動(dòng)態(tài)添加的视粮,必須在第一次下載后打開App细办,才能出現(xiàn)Home Screen Quick Actions。
1. 通過Plist文件靜態(tài)設(shè)置
在應(yīng)用的 Info.plist 文件中添加UIApplicationShortcutItems
數(shù)組蕾殴。
數(shù)組中添加字典笑撞,如下圖所示:
其中,字典的Key有以下選項(xiàng):
名稱 | 說明 | 是否必須 |
---|---|---|
UIApplicationShortcutItemTitle | 標(biāo)簽的標(biāo)題 | 必填 |
UIApplicationShortcutItemType | 標(biāo)簽的唯一標(biāo)識(shí) | 必填 |
UIApplicationShortcutItemIconType | 使用系統(tǒng)圖標(biāo)的類型钓觉,如搜索茴肥、定位、home等 | 可選 |
UIApplicationShortcutItemIconFile | 使用項(xiàng)目中的圖片作為標(biāo)簽圖標(biāo) | 可選 |
UIApplicationShortcutItemSubtitle | 標(biāo)簽副標(biāo)題 | 可選 |
UIApplicationShortcutItemUserInfo | 字典信息荡灾,如傳值使用 | 可選 |
第一個(gè)圖片使用系統(tǒng)自帶的瓤狐,第二個(gè)是使用Assets.xcassets
文件夾中的圖片,當(dāng)完成設(shè)置后批幌,效果如下:
2. 通過代碼動(dòng)態(tài)添加
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個(gè)芬首。
無論用哪種方式添加,當(dāng)點(diǎn)擊item后逼裆,都會(huì)調(diào)用
AppDelegate
中的application(_:performActionFor:completionHandler:)
方法:
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
print(shortcutItem.type) // 通過type來判斷是點(diǎn)擊了哪一個(gè)按鈕
}
三郁稍、Peek and Pop(預(yù)覽與跳轉(zhuǎn))
- Peek:輕按,屏幕視圖就會(huì)過渡到Peek胜宇,一個(gè)你設(shè)置的用來展示更多內(nèi)容的視圖-就像Mail app做的一樣耀怜。如果用戶這時(shí)結(jié)束了觸碰,Peek就會(huì)消失并且應(yīng)用回到交互開始之前的狀態(tài)桐愉。當(dāng)你用力按下屏幕按到一定程度時(shí)财破,系統(tǒng)會(huì)彈出一個(gè)預(yù)覽視圖,這個(gè)過程就稱之為Peek从诲。
- Pop:或者這個(gè)時(shí)候左痢,用戶可以在peek界面上更用力按下來跳轉(zhuǎn)到使用peek呈現(xiàn)的視圖,這個(gè)過渡動(dòng)畫會(huì)使用系統(tǒng)提供的pop過渡。pop出來的視圖會(huì)填滿你應(yīng)用的根視圖并顯示一個(gè)返航按鈕可以回到交互開始的地方。再用力按下去就會(huì)展開到預(yù)覽視圖的控制器俊性,這過程就是Pop略步。
實(shí)現(xiàn)步驟:
- 注冊(cè)預(yù)覽代理
// Registers a view controller to participate with 3D Touch preview (peek) and commit (pop).
@available(iOS 9.0, *)
// 第一個(gè)參數(shù):代理
// 第二個(gè)參數(shù):哪個(gè)view執(zhí)行Peek
open func registerForPreviewing(with delegate: UIViewControllerPreviewingDelegate, sourceView: UIView) -> UIViewControllerPreviewing
- 遵守協(xié)議:
UIViewControllerPreviewingDelegate
- 實(shí)現(xiàn)協(xié)議方法
// 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)
接下來用一個(gè)tableView的例子??來說明,實(shí)現(xiàn)以下效果:
代碼如下:
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)行") }
// 注冊(cè)Cell
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
// 判斷系統(tǒng)版本定页,必須iOS 9及以上趟薄,同時(shí)檢測(cè)是否支持觸摸力度識(shí)別
if #available(iOS 9.0, *), traitCollection.forceTouchCapability == .available {
// 注冊(cè)預(yù)覽代理,self監(jiān)聽典徊,tableview執(zhí)行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) {
// 模態(tài)彈出需要展現(xiàn)的控制器
showDetailViewController(viewControllerToCommit, sender: nil)
// 通過導(dǎo)航欄push需要展現(xiàn)的控制器
// 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 }
// 設(shè)置Peek視圖突出顯示的frame
previewingContext.sourceRect = cell.frame
let vc = DetalViewController()
// 返回需要彈出的控制權(quán)
return vc
}
}
在實(shí)際開發(fā)中杭煎,你可能會(huì)用到 UIView中的坐標(biāo)轉(zhuǎn)換 的幾個(gè)方法(可跳過不看):
// 將像素point由point所在視圖轉(zhuǎn)換到目標(biāo)視圖view中,返回在目標(biāo)視圖view中的像素值
open func convert(_ point: CGPoint, to view: UIView?) -> CGPoint
// 例如:point2 = view1.convert(point1, toView: view2):把point1從view1的坐標(biāo)系中卒落,轉(zhuǎn)換到view2的坐標(biāo)系中
// 將像素point從view中轉(zhuǎn)換到當(dāng)前視圖中羡铲,返回在當(dāng)前視圖中的像素值
open func convert(_ point: CGPoint, from view: UIView?) -> CGPoint
// 例如:point2 = view1.convert(point1, from: view2):把point1從view2的坐標(biāo)系中,轉(zhuǎn)換到view1的坐標(biāo)系中
// 將rect由rect所在視圖轉(zhuǎn)換到目標(biāo)視圖view中儡毕,返回在目標(biāo)視圖view中的rect
open func convert(_ rect: CGRect, to view: UIView?) -> CGRect
// 例如:rect2 = view1.convert(rect1, toView: view2):把rect1從view1的坐標(biāo)系中也切,轉(zhuǎn)換到view2的坐標(biāo)系中
// 將rect從view中轉(zhuǎn)換到當(dāng)前視圖中,返回在當(dāng)前視圖中的rect
open func convert(_ rect: CGRect, from view: UIView?) -> CGRect
// 例如:rect2 = view1.convert(rect1, toView: view2):把rect1從view2的坐標(biāo)系中妥曲,轉(zhuǎn)換到view1的坐標(biāo)系中
四、Peek快速選項(xiàng)
如果用戶一直保持觸摸钦购,可以向上滑動(dòng)Peek視圖檐盟,系統(tǒng)會(huì)展示出你預(yù)先設(shè)置和peek關(guān)聯(lián)的peek快速選項(xiàng)。
每一項(xiàng)peek快速選項(xiàng)都是你應(yīng)用中的深度鏈接押桃。當(dāng)peek快速選項(xiàng)出現(xiàn)后葵萎,用戶可以停止觸摸而且peek會(huì)停留在屏幕中。用戶可點(diǎn)擊一個(gè)快速選項(xiàng)唱凯,喚出相關(guān)鏈接羡忘。
在本例中,實(shí)現(xiàn)以上效果磕昼,只需要在
DetalViewController
中添加以下代碼即可:
import UIKit
class DetalViewController: UIViewController {
@available(iOS 9.0, *)
lazy var previewActions: [UIPreviewActionItem] = {
let a = UIPreviewAction(title: "這是一個(gè)default按鈕", style: .default, handler: { (action, vc) in
// 這里實(shí)現(xiàn)點(diǎn)擊按鈕事件處理
})
let b = UIPreviewAction(title: "這是一個(gè)destructive按鈕", style: .destructive, handler: { (action, vc) in
// 這里實(shí)現(xiàn)點(diǎn)擊按鈕事件處理
})
return [a, b]
}()
@available(iOS 9.0, *)
override var previewActionItems: [UIPreviewActionItem] {
return previewActions
}
}
最后注意:以上全部功能必須要求為 iPhone 6s 及以上機(jī)型卷雕,并且是 iOS 9 及以上,才有效果票从,模擬器可以看到效果漫雕,不需要安裝任何插件,但必須要有觸摸盤才行峰鄙,在觸摸盤上的點(diǎn)擊就是3D Touch浸间。