はじめに
WKWebViewの読み込み状況をUIProgressViewで表示する実装について試したので、記事に残します。
サンプルイメージ
開発環境
- macOS Big Sur 11.2.3
- Xcode 12.4
- Swift 5.3.2
本題
実装方針
WKWebViewのサブビューとしてUIProgressViewを追加し、UIViewRepresentableを使ってSwiftUIのプロジェクトでも使えるようにする。
実装
WebView.swift
import SwiftUI import WebKit struct WebView: UIViewRepresentable { var webView = WKWebView() var progressView = UIProgressView() let urlString: String class Coordinator: NSObject { var parent: WebView init(_ parent: WebView) { self.parent = parent } // WebViewの読み込み状況を監視する func addProgressObserver() { parent.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { // progressViewのアニメーション処理 if keyPath == "estimatedProgress" { parent.progressView.alpha = 1.0 parent.progressView.setProgress(Float(parent.webView.estimatedProgress), animated: true) if parent.webView.estimatedProgress >= 1.0 { UIView.animate(withDuration: 0.2, delay: 0.0, options: [.curveEaseOut], animations: { [weak self] in self?.parent.progressView.alpha = 0.0 }, completion: { (finished: Bool) in self.parent.progressView.setProgress(0.0, animated: false) }) } } } } func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIView(context: Context) -> WKWebView { webView.addSubview(progressView) // UIProgressViewのレイアウト設定 progressView.translatesAutoresizingMaskIntoConstraints = false progressView.widthAnchor.constraint(equalTo: webView.widthAnchor, multiplier: 1.0).isActive = true progressView.topAnchor.constraint(equalTo: webView.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true progressView.leadingAnchor.constraint(equalTo: webView.leadingAnchor, constant: 0).isActive = true return webView } func updateUIView(_ webView: WKWebView, context: Context) { context.coordinator.addProgressObserver() guard let url = URL(string: urlString) else { return } let request = URLRequest(url: url) webView.load(request) } }
ContentView.swift(WebViewの使用例)
import SwiftUI struct ContentView: View { var body: some View { WebView(urlString: "{表示したいURL}") } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
おわりに
今回のサンプルではUIProgressViewのレイアウトに問題があったり、SwiftUIのProgressViewを活用できていないなど課題が残っているので記事にするか迷ったのですが、本記事のテーマに関する外部の記事が少ないこともあり、一旦動くサンプルを共有することにも意味はあるかと思い記事にしました。
※このブログのWebViewに関する記事は、以下のリンクでまとめて見ることができます。
WebView カテゴリーの記事一覧 - Swift・iOS
参考
- https://developer.apple.com/documentation/webkit/wkwebview
-
https://developer.apple.com/documentation/uikit/uiprogressview
- https://developer.apple.com/documentation/swiftui/uiviewrepresentable
-
swift - How to observe loading progress for WKWebView in SwiftUI? - Stack Overflow
-
WKWebViewのestimatedProgressが1.0になったら自然にUIProgressViewが非表示になるように見せる - Qiita
-
Creating Simple Web Browser with WKWebView & UINavigationController · GitHub
-
https://developer.apple.com/documentation/swiftui/progressview