#42 3D touch2- peek & pop 基本設定

目的:實作peek & pop 基本設定,預覽與彈出功能可減少在不同app往返的時間

1.在上一章的基礎上,建立畫面,新增兩個view controller
(1)label:peek,storyboard id:peek
(2)label:pop,storyboard id:pop

2.在FirstViewController的viewDidLoad()中確認有支援3D touch

override func viewDidLoad() {
super.viewDidLoad()

//確認有支援3D touch
if traitCollection.forceTouchCapability == .available{
//註冊這個功能
//with:UIViewControllerPreviewingDelegate: 如果使用者真的3D touch,是誰要負責處理這個事件
//sourceView:UIView: 哪一個視圖負責接受3D touch這個觸碰
registerForPreviewing(with: self, sourceView: view)
}

3.registerForPreviewing(with: self):
self要服從UIViewControllerPreviewingDelegate,故加入UIViewControllerPreviewingDelegate,並加入方法

class FirstViewController: UIViewController,UIViewControllerPreviewingDelegate {

//使用者在按壓預覽時看到的畫面,並把畫面回傳出來(peek)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "peek")
}

//使用者重壓時會看到的畫面(pop)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
if let popVC = storyboard?.instantiateViewController(withIdentifier: "pop") as? popViewController{
present(popVC, animated: true, completion: nil)
}
}

4.新建popViewController,拉進按鈕back,點選按鈕回到上個畫面

@IBAction func back(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}

5.設定只有按到FirstView文字才會觸發功能

點選label,在storyboard上先勾選user interaction enabled
勾選後文字標籤才能接受3D touch

拉進label,命名成firstViewLabel,確認有支援3D touch的方法中將sourceView改成firstViewLabel
* 因文字標籤是UIView的子類別(所有在畫面上看到的元件都是),故可直接替換

//確認有支援3D touch
if traitCollection.forceTouchCapability == .available{
//註冊這個功能
//with:UIViewControllerPreviewingDelegate: 如果使用者真的3D touch,是誰要負責處理這個事件
//self要服從UIViewControllerPreviewingDelegate
//sourceView:UIView: 哪一個視圖負責接受3D touch這個觸碰
registerForPreviewing(with: self, sourceView: firstViewLabel)
}

6.傳值到pop彈出的畫面

(1)在popViewController內拉進popLabel

class popViewController: UIViewController {


@IBOutlet weak var popLabel: UILabel!

(2)加入變數

var infoFromViewOne:String?

(3)回到FirstViewController中改寫pop方法

//使用者重壓時會看到的畫面(pop)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
if let popVC = storyboard?.instantiateViewController(withIdentifier: "pop") as? popViewController{
//讓firstViewLabel的文字與infoFromViewOne相同
//再到popViewController將popLabel.text = infoFromViewOne
popVC.infoFromViewOne = firstViewLabel.text
present(popVC, animated: true, completion: nil)
}
}

(4)在popViewController的viewDidLoad()加入popLabel.text = infoFromViewOne

override func viewDidLoad() {
super.viewDidLoad()
popLabel.text = infoFromViewOne

// Do any additional setup after loading the view.
}

7.tableView上的 3D touch

(1)在SecondViewController拉進table view,命名:myTableView,實作UITableViewDelegate, UITableViewDataSource方法

import UIKit

class SecondViewController: UIViewController , UITableViewDelegate, UITableViewDataSource, UIViewControllerPreviewingDelegate{

@IBOutlet weak var myTableView: UITableView!

let appleProducts = ["iPhone", "iPad", "Apple Watch"]

func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return appleProducts.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = appleProducts[indexPath.row]
return cell
}

(2)確認有支援3D touch

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

//確認有支援3D touch
if traitCollection.forceTouchCapability == .available{
registerForPreviewing(with: self, sourceView: myTableView)

}

}

(3)加入peek & pop

//使用者在按壓預覽時看到的畫面,並把畫面回傳出來(peek)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
//location:觸控時接觸的那個點
//整行程式為點選到的那一格的indexPath row
if let selectedRow = myTableView.indexPathForRow(at: location)?.row{
selectedProduct = appleProducts[selectedRow]
return storyboard?.instantiateViewController(withIdentifier: "peek")
}else{
return nil
}

}

//使用者重壓時會看到的畫面(pop)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
//先確認selectedProduct不等於nil
guard selectedProduct != nil else{return}

if let popVC = storyboard?.instantiateViewController(withIdentifier: "pop") as? popViewController{
//已知selectedProduct = appleProducts[selectedRow]
popVC.infoFromViewOne = selectedProduct
//點選後將selectedProduct設回nil
selectedProduct = nil
present(popVC, animated: true, completion: nil)
}
}

8.在popViewController中偵測按壓在畫面上的力量

//實作觸碰時顯示按壓力度的方法
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
//touches:複數觸碰點(可能同時有多根手指)
if let touch = touches.first{
//確認有無3D touch
if traitCollection.forceTouchCapability == .available{
//touch.force按壓值
popLabel.text = "\(touch.force) "

}
}
}

9.完整程式碼及畫面展示

在FirstViewController中

import UIKit

class FirstViewController: UIViewController,UIViewControllerPreviewingDelegate {


@IBOutlet weak var firstViewLabel: UILabel!

//使用者在按壓預覽時看到的畫面,並把畫面回傳出來(peek)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "peek")
}

//使用者重壓時會看到的畫面(pop)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
if let popVC = storyboard?.instantiateViewController(withIdentifier: "pop") as? popViewController{
//讓firstViewLabel的文字與infoFromViewOne相同
//再到popViewController將popLabel.text = infoFromViewOne
popVC.infoFromViewOne = firstViewLabel.text
present(popVC, animated: true, completion: nil)
}
}

override func viewDidLoad() {
super.viewDidLoad()
let myItem3 = UIApplicationShortcutItem(type: "com.phrase.threeDTouchBasic.gotothird", localizedTitle: "third", localizedSubtitle: "go to second", icon: UIApplicationShortcutIcon(type: .search), userInfo: nil)
let myItem4 = UIApplicationShortcutItem(type: "com.phrase.threeDTouchBasic.gotofourth", localizedTitle: "fourth", localizedSubtitle: "go to fourth", icon: UIApplicationShortcutIcon(type: .pause), userInfo: nil)

//shared:找到目前應用程式的實體
//shortcutItems:設定3D touch跳出動態的選項是......
UIApplication.shared.shortcutItems = [myItem3,myItem4]

//確認有支援3D touch
if traitCollection.forceTouchCapability == .available{
//註冊這個功能
//with:UIViewControllerPreviewingDelegate: 如果使用者真的3D touch,是誰要負責處理這個事件
//self要服從UIViewControllerPreviewingDelegate
//sourceView:UIView: 哪一個視圖負責接受3D touch這個觸碰
registerForPreviewing(with: self, sourceView: firstViewLabel)
}
}

}

在SecondViewController中

import UIKit

class SecondViewController: UIViewController , UITableViewDelegate, UITableViewDataSource, UIViewControllerPreviewingDelegate{

@IBOutlet weak var myTableView: UITableView!

let appleProducts = ["iPhone", "iPad", "Apple Watch"]

//建立變數以供peek的程式取用
var selectedProduct:String?


override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

//確認有支援3D touch
if traitCollection.forceTouchCapability == .available{
registerForPreviewing(with: self, sourceView: myTableView)

}

}


func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return appleProducts.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = appleProducts[indexPath.row]
return cell
}



//使用者在按壓預覽時看到的畫面,並把畫面回傳出來(peek)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
//location:觸控時接觸的那個點
//整行程式為點選到的那一格的indexPath row
if let selectedRow = myTableView.indexPathForRow(at: location)?.row{
selectedProduct = appleProducts[selectedRow]
return storyboard?.instantiateViewController(withIdentifier: "peek")
}else{
return nil
}

}

//使用者重壓時會看到的畫面(pop)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
//先確認selectedProduct不等於nil
guard selectedProduct != nil else{return}

if let popVC = storyboard?.instantiateViewController(withIdentifier: "pop") as? popViewController{
//已知selectedProduct = appleProducts[selectedRow]
popVC.infoFromViewOne = selectedProduct
//點選後將selectedProduct設回nil
selectedProduct = nil
present(popVC, animated: true, completion: nil)
}
}


}

在popViewController中

import UIKit

class popViewController: UIViewController {


@IBOutlet weak var popLabel: UILabel!

@IBAction func back(_ sender: UIButton) {
//回到上個畫面
dismiss(animated: true, completion: nil)
}

var infoFromViewOne:String?


override func viewDidLoad() {
super.viewDidLoad()
popLabel.text = infoFromViewOne

// Do any additional setup after loading the view.
}

//實作觸碰時顯示按壓力度的方法
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
//touches:複數觸碰點(可能同時有多根手指)
if let touch = touches.first{
//確認有無3D touch
if traitCollection.forceTouchCapability == .available{
//touch.force按壓值
popLabel.text = "\(touch.force) "

}
}
}
}

--

--