#11WKWebView(KOV)

Apple程式範例檔5

基本上是複製Apple程式範例檔的程式碼,但詳細打上自己的註解和開發者文件上的資料.畢竟唯有打上註解,分析理解後,東西才可能變成自己的東西.

程式功能:模擬網頁開啟的狀態

能開啟的網頁,當然就是我們的程式男神,情歌王子,swfit課程界的第一把交椅,彼得潘大神的Medium教室啦.讓我們先介紹會用到實作技術.

實作技術:

  • WKWebView
  • KOV(Key-Value Observing)
  • webView的navigationDelegate
  • UIAlertController

KOV(Key-Value Observing)是我第一次聽到技術,實際理解後,發現跟NotificationCenter有點像呢.不過KOV似乎比較陽春一點.基本上就是觀察某個特定的元件,當元件發生變化時,同步進行改動.

讓我們開始Coding吧!

寫好變數和資料

//用程式生成元件
var webView: WKWebView!
var progressView: UIProgressView!

//網頁名稱
var websites = ["medium.com/彼得潘的-swift-ios-app-開發教室","github.com","google.com"]

//顯示網頁
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}

生成按鈕

//設計按鈕
override func viewDidLoad() {
super.viewDidLoad()
title = "網頁瀏覽器"

//右上角按鈕
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "開啟", style: .plain, target: self, action: #selector(openTapped))

//最下面的東西是WKNavigation
//空白按鈕
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)

//重新下載WebView
let refresh = UIBarButtonItem(barButtonSystemItem: .refresh, target: webView, action: #selector(webView.reload))

//上一頁
let back = UIBarButtonItem(barButtonSystemItem: .rewind, target: webView, action: #selector(webView.goBack))
//下一頁
let forward = UIBarButtonItem(barButtonSystemItem: .fastForward, target: webView, action: #selector(webView.goForward))

//任務條
progressView = UIProgressView(progressViewStyle: .default)
progressView.sizeToFit()
//把View加進Item
let progressButton = UIBarButtonItem(customView: progressView)

//按鈕陣列 底下的bar. webView
toolbarItems = [progressButton, back, forward, spacer, refresh]
//解開隱藏
navigationController?.isToolbarHidden = false

/*options 參數可以使用入以下內容:

new:表示更改字典應要提供新的屬性值(如果適用)

old:表示更改字典應要包含舊的屬性值(如果適用)

initial:如果指定,則在觀察者註冊方法返回之前應立即向觀察者發送通知。

prior:是否應該在每次更改前後向觀察者發送單獨的通知,而不是更改後的單個通知。*/


//KOV!!!!!!
//觀察WKWebView的estimatedProgress(估計進度)
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)


//控制 前進或後退的手勢讓按鈕可以點擊
webView.allowsBackForwardNavigationGestures = true
}

右上角按紐執行的函式,其中又包含AlertAction的函式

@objc func openTapped() {
let ac = UIAlertController(title: "開啟網頁...", message: nil, preferredStyle: .actionSheet)

//按鈕
for website in websites {
ac.addAction(UIAlertAction(title: website, style: .default, handler: openPage))
}

ac.addAction(UIAlertAction(title: "取消", style: .destructive))
present(ac, animated: true)
}

// 是用UIAlertAction進行動作觸發
func openPage(action: UIAlertAction) {
guard let actionTitle = action.title else {
return
}

//有的話,設計成網址
if websites.contains(actionTitle) {
guard let url = URL(string:("https://" + actionTitle).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!) else {
return
}
//開啟網頁
webView.load(URLRequest(url: url))
}
}

KOV設值的部分!

/*keyPath
相對於object的金鑰路徑,與已更改的值相對於。

object
key Path的源物件。

change
描述對鍵路徑keyPath相對於object的屬性值所做的更改的字典。 條目在Change Dictionary Keys中描述。

context
觀察者註冊接收關鍵值觀察通知時提供的值。*/

//addObserver的設定值
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "estimatedProgress" {
//顯示進度條
progressView.progress = Float(webView.estimatedProgress)
//顯示估計網路載入
}
}

加碼附上 特定條件下 網站才能被開啟的函式

加了這行,彼得潘大神的網站就開不起來了.因為中文網址要轉碼,跟原先的網址就不一樣了

/*webView
導航請求開始的網路檢視。
navigationAction
有關觸發導航請求的操作的詳細資訊。

decidePolicyFor
方針
decisionHandler
一個完成處理程式塊,用於呼叫結果是否允許或取消導航。 此處理程式沒有返回值,並接受以下引數*/
//@escaping 取自函式外的參數

//開啟網站的方針
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

// 只有設定好的網址才能開啟
let url = navigationAction.request.url

if let host = url?.host {

for website in websites {

if host.contains(website) {
//允許開啟
decisionHandler(.allow)
return
}
}
//不允許開啟,跳出alert
let ac = UIAlertController(title: "這個網站被封鎖了", message: "請從網站列表選擇.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Open List of allowed websites", style: .default, handler: openPage))
present(ac,animated: true)
}
decisionHandler(.cancel)
}

程式連結:

參考資料:

--

--