①⓪③ 透過 present 顯示 iOS SDK內建的 Controller(1)
SFSafariViewController, UIActivityViewController, UIAlertController, AVPlayerViewController & UIReferenceLibraryViewController
練習目標:
一句話說明今天的練習:
做出平常在 App 裡能夠顯示網頁、分享照片等等的功能!
什麼是 Present?
Presents a view controller modally. 官方的定義是:用 modally 的方式呈現一個 view controller。
modally 是使用 storyboard 來 segue controller 時,沒有用 navigation controller 控制大家會呈現的樣式。
PS. 使用 present 時,通常輸入完希望呈現的 controller 與需要動畫效果之後,會看到 completion 後面有(() -> Void?
如果沒有其他要做的事情,僅僅呈現 controller 就好,這邊輸入 nil 即可。否則直接在此看下 enter 鍵,將自動創建大括號{}讓你輸入其餘的程式。
今天將練習使用 present 以下 controller:
- SFSafariViewController 顯示網頁
- UIActivityViewController 分享圖片與文字
- UIAlertController 警告訊息
- AVPlayerViewController 播放影片
- UIReferenceLibraryViewController 查詢單字
其他 controller 要搭配 data source 或 delegate 才能實現完整的功能,之後在 part 2 練習。
SFSafariViewController
因為看到 Safari,可知是顯示網頁的 controller。
viewDidAppear
為了實驗一打開 App 就出現網頁(到底誰會這樣做?)將程式寫在 viewDidAppear 方法中:
import UIKit
import SafariServices // 顯示網頁必輸入 SafariServices
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
// view 已載入並顯示後的方法
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let url = URL(string: "https://medium.com/@lebonthe") {
let controller = SFSafariViewController(url: url)
present(controller, animated: true, completion: nil)
}
}
}
button
點一下按鈕出現網址:
@IBOutlet weak var button: UIButton!
@IBAction func buttonTapped(_ sender: UIButton) {
if let url = URL(string: "https://medium.com/@lebonthe"){
let controller = SFSafariViewController(url: url)
present(controller, animated: true, completion: nil)
}
}
UIActivityViewController
可以分享圖片與文字。(實機中才會出現 FB 或 LINE 選項)
程式
@IBAction func buttonTapped(_ sender: UIButton) {
let controller = UIActivityViewController(activityItems: ["Min 的 Medium", UIImage(named: "cat_koubakozuwari_brown")!, URL(string: "https://medium.com/@lebonthe")!], applicationActivities: nil)
present(controller, animated: true, completion: nil)
}
在 activityItems: 後面的陣列,決定分享的內容格式:
“” 是文字
UIImage(name: ) 是圖片
URL(string: ) 是網址
注意
在實驗之前,先看有兩件事情要注意:
- 第一是將圖片存到手機相簿時,需在 App 的 Info 頁面設定 Privacy NSPhotoLibraryAddUsageDescription:
接著在 value 欄輸入給使用者的訊息文字:
參考:
- 第二是 iPad 要注意的。當在 iPad present UIActivityViewController 時,如果沒有設定彈出框顯示的位置,會造成閃退。因此要設定 sourceView 來指定顯示位置:
@IBAction func share(_ sender: UIButton) {
let controller = UIActivityViewController(activityItems: ["Min 的 Medium", UIImage(named: "cat_koubakozuwari_brown")!, URL(string: "https://medium.com/@lebonthe")!], applicationActivities: nil)
controller.popoverPresentationController?.sourceView = sender
present(controller, animated: true, completion: nil)
}
參考:
接著使用剛剛的程式,陣列裡包含字串、圖片與網址,看看分享的結果:
分享圖片後儲存:
分享文字與網址:
將網址存到 Reading List:
由以上三種方式可知,即便 array 中有三種不同的格式,在分享後會依據分享的方式,留下可分享的內容。
iPad 實測 — 這是加了 sourceView 的,沒有加 controller.popoverPresentationController?.sourceView = sender
的話的確什麼都顯示不出來:
UIAlertController
UIAlertController 可跳出警告、提示,並且可以做成選單。多種玩法請往下觀看:
參考:
alert style 顯示提示-畫面中間彈出的警告訊息
使用 UIAlertAction 生成視窗上的按鈕:
@IBOutlet weak var button: UIButton!
@IBOutlet weak var textField: UITextField!
@IBAction func buttonTapped(_ sender: UIButton) {
if textField.text?.isEmpty == true {
let controller = UIAlertController(title: "怎麼可以忘了!", message: "不知道好歹也要猜一下", preferredStyle: .alert)
let okAction = UIAlertAction(title: "好吧", style: .default)
controller.addAction(okAction)
present(controller, animated: true)
}
}
UIAlertAction 的參數 style 控制按鈕文字的顏色,default 與 .cancel 是藍色,.destructive 是紅色。透過設定 UIAlertController 的 view.tintColor 可以調整 default 與 .cancel 的顏色:
controller.view.tintColor = .orange
不只一次 addAction 可加入多個按鈕,顯示在視窗上的位置依照加入先後的順序而定:
設定點選按鈕時做的事情
以 UIAlertAction 的 handler 參數傳入 closure 控制點選按鈕後執行的事情:
let noAction = UIAlertAction(title: "告訴我", style: .destructive) { _ in
self.label.isHidden = false
}
如果按鈕設定成 .cacel 的樣式,則自動設定在左邊:
在彈窗中顯示文字輸入框
從 controller.addTextField 的參數 configurationHandler 傳入 closure 設定樣式:
@IBAction func buttonTapped(_ sender: UIButton) {
let controller = UIAlertController(title: "登入", message: "請輸入帳號密碼", preferredStyle: .alert)
controller.addTextField { textField in
textField.placeholder = "帳號"
textField.keyboardType = UIKeyboardType.emailAddress
}
controller.addTextField { textField in
textField.placeholder = "密碼"
textField.keyboardType = UIKeyboardType.phonePad
textField.isSecureTextEntry = true
}
let okAction = UIAlertAction(title: "OK", style: .default) { [unowned controller] _ in
let account = controller.textFields?[0].text
let password = controller.textFields?[1].text
self.label.text = "\(account!) 成功登入"
}
controller.addAction(okAction)
let cancelAction = UIAlertAction(title: "取消", style: .cancel)
controller.addAction(cancelAction)
present(controller, animated: true)
}
}
actionSheet style — 由下而上彈出的選單視窗
@IBAction func buttonTapped(_ sender: UIButton) {
let controller = UIAlertController(title: "MLB問題", message: "請問下列哪位選手會出現在2024年的道奇隊", preferredStyle: .actionSheet)
let things = ["大谷翔平","大谷","翔平"]
for thing in things {
let action = UIAlertAction(title: thing, style: .default) { action in
print(action.title ?? 0)
}
controller.addAction(action)
}
let cancelAction = UIAlertAction(title: "以上皆非", style: .cancel)
controller.addAction(cancelAction)
present(controller, animated: true)
}
}
同 SFSafariViewController,在 iPad 顯示 action sheet 也要記得設定彈出框顯示的位置。
其他相關:
AVPlayerViewController
AVPlayerView 可播放影片:
先到 apple 的預告片找預告片網址:
目前apple官網似乎沒有可以直接播放的連結了,只好先看簡體的:
@IBAction func buttonTapped(_ sender: UIButton) {
if let url = URL(string: "https://vfx.mtime.cn/Video/2023/06/30/mp4/230630103537478111.mp4"){
let player = AVPlayer(url: url)
let controller = AVPlayerViewController()
controller.player = player
present(controller, animated: true) {
player.play()
}
}
}
UIReferenceLibraryViewController
這個 controller 可以查詢單字,但用模擬器無法測試,要裝到手機上。
參考:
為了查詢單字,先去 iOS 的 Settings>General>Dictionary 內加入字典。使用模擬器嘗試做這件事果然得到一片空白:
打開手機裡的 Dictionary,發現原來已經有非常多字典了:
@IBAction func buttonTapped(_ sender: UIButton) {
let controller = UIReferenceLibraryViewController(term: textField.text!)
present(controller, animated: true)
}
使用 iPhone SE2 測試:
謝謝收看!