在 iPhone & iPad 上顯示 popover 彈出視窗
在 iPad 上我們時常看到如上圖紅色框框的 popover 彈出視窗,它可以讓原本佔滿整個螢幕的 controller 畫面瘦身,變成只佔滿螢幕的一部分。這樣子的功能其實不是 iPad 獨有,iPhone 也做得到。接下來就讓我們一步步實現 popover 的效果吧。
新版做法: iOS 14 以上版本,包含 14
使用 Pull Down Button & Pop Up Button。
iOS 的選單(menu)按鈕 — Pull Down Button & Pop Up Button
從 iOS 14 開始,我們可以更方便地製作選單按鈕,呈現類似下拉式選單的效果。
medium.com
舊版做法: iOS 14 之前
在 iPad 上顯示 Popover
我們希望點選 + 後,選擇角色的表格以 popover 呈現。
就像魔法一樣,只要拉 segue 時選擇 Present As Popover 即可實現彈出視窗的效果。
在 iPhone 上顯示 Popover
然而同樣的程式,跑在 iPhone 上卻讓我們明白童話都是騙人的。按了 + 之後,表格還是佔滿整個螢幕。
其實 iPhone 還是能夠做到 popover,只是比較麻煩。我們還要加入以下程式。
1 將第一頁的 controller 設為 UIPopoverPresentationController 物件的 delegate。
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate { override func prepare(for segue: UIStoryboardSegue, sender: Any?) { segue.destination.popoverPresentationController?.delegate = self }
當我們以 popover 方式呈現第二頁的 table controller 時,此時將自動生成 UIPopoverPresentationController 物件幫忙控制 popover。而我們可透過定義 UIPopoverPresentationControllerDelegate 的 function 控制 popover。
因此我們讓第一頁的 controller 遵從 protocol UIPopoverPresentationControllerDelegate,然後在 function prepare 裡利用 segue.destination.popoverPresentationController
讀取 UIPopoverPresentationController 物件,然後將 controller 設成它的 delegate 。
2 定義 UIPopoverPresentationControllerDelegate 的 function adaptivePresentationStyle(for:traitCollection:)
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { return .none}
為了讓 iPhone 也能顯示 popover,我們必須在此 method 裡回傳 presentation style .none。
修改 Popover 的大小
修改 popover 顯示的 controller 的 preferredContentSize,即可控制 popover 的大小。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { segue.destination.preferredContentSize = CGSize(width: 150, height: 200) segue.destination.popoverPresentationController?.delegate = self}
從程式 present controller 實現 popover 的效果。
我們也可以不透過 segue,從程式 present controller 實現 popover 的效果。
以 iPad App 為例:
@IBAction func buttonPressed(_ sender: Any) { if let controller = storyboard?.instantiateViewController(withIdentifier: "TableViewController") { controller.modalPresentationStyle = .popover controller.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem present(controller, animated: true, completion: nil) }}
說明:
1 controller.modalPresentationStyle = .popover
以 popover 的效果呈現。
2 controller.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
讓 popover 的箭頭指到 rightBarButtonItem。
讓 popover 的箭頭指到某個特定的 view。
剛剛我們透過 barButtonItem 指定 popover 的箭頭指到 bar 上的 button,但我們也可利用 sourceView 讓它指到某個特定的 view。
@IBAction func buttonPressed(_ sender: Any) { if let controller = storyboard?.instantiateViewController(withIdentifier: "TableViewController") { controller.modalPresentationStyle = .popover controller.popoverPresentationController?.sourceView = eyeSwitch present(controller, animated: true, completion: nil) }}
如上圖所示,現在箭頭完美地指到 switch 開關。可惜它有個小小的缺點,它指到了 switch 的左上方,因為 popover 預設會指到 sourceView 的左上方。
沒關係,只要設定 UIPopoverPresentationController 的 sourceRect,即可控制箭頭指到的位置。
controller.popoverPresentationController?.sourceRect = CGRect(origin: .zero, size: eyeSwitch.frame.size)
從 segue 控制 popover 箭頭指到的對象。
從 segue 也可以設定 popover 箭頭指到的對象。如下圖所示,Anchor 欄位代表箭頭指到的對象,因此從 Anchor 右邊的空心圓圈拉線到我們希望箭頭指到的 view 即可。