はじめに
Qiitaに書くほどではないとは思いますが、
UIKit初心者の自分からしたらどうやってやるの?ポイントだったので記事にしておきます
やろうとしてること
① UIViewControllerでWKWebViewを表示します
② 作ったUIViewControllerをUIViewControllerRepresentableでViewにします
③ SwiftUI側でsheetで表示します
問題点
iPadのsheet
は全画面ではないのでWebViewがはみ出る
iPhone | iPad |
---|---|
修正前のコード
import UIKit
import WebKit
import SwiftUI
struct WebView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> WebViewController {
return WebViewController()
}
func updateUIViewController(_ uiViewController: WebViewController, context: Context) { }
}
class WebViewController: UIViewController {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView = WKWebView(frame: view.frame)
view.addSubview(webView)
webView.customUserAgent = "Mozilla/5.0 (\(UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad"); CPU \(UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad") OS \(UIDevice.current.systemVersion.replacingOccurrences(of: ".", with: "_")) like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1"
let url = URLRequest(url: URL(string: "https://mobile.twitter.com/i/flow/login")!)
webView.load(url)
}
}
import SwiftUI
struct ContentView: View {
@State var isWebView: Bool = false
var body: some View {
Button("ログイン画面表示") {
isWebView = true
}
.sheet(isPresented: $isWebView) {
WebView()
}
}
}
修正後のコード
import UIKit
import WebKit
import SwiftUI
struct WebView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> WebViewController {
return WebViewController()
}
func updateUIViewController(_ uiViewController: WebViewController, context: Context) { }
}
class WebViewController: UIViewController {
var webView: WKWebView!
+ override func viewWillLayoutSubviews() {
+ webView.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
+ webView.heightAnchor.constraint(equalToConstant: view.bounds.height).isActive = true
+ }
override func viewDidLoad() {
super.viewDidLoad()
- webView = WKWebView(frame: view.frame)
+ webView = WKWebView(frame: .zero)
+ webView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(webView)
webView.customUserAgent = "Mozilla/5.0 (\(UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad"); CPU \(UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad") OS \(UIDevice.current.systemVersion.replacingOccurrences(of: ".", with: "_")) like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1"
let url = URLRequest(url: URL(string: "https://mobile.twitter.com/i/flow/login")!)
webView.load(url)
}
}
import SwiftUI
struct ContentView: View {
@State var isWebView: Bool = false
var body: some View {
Button("ログイン画面表示") {
isWebView = true
}
.sheet(isPresented: $isWebView) {
WebView()
}
}
}
iPhone | iPad |
---|---|
解説
UIViewControllerのライフサイクルを理解していなかったのが原因だと思います。
viewDidLoad
でsheet
のframeがとれるわけが無いので今考えたら当然って感じがしますが笑
試したこと1
最初にやったのはviewWillLayoutSubviews
でWebViewを生成してみました。
override func viewWillLayoutSubviews() {
webView = WKWebView(frame: view.frame)
view.addSubview(webView)
webView.customUserAgent = "Mozilla/5.0 (\(UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad"); CPU \(UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad") OS \(UIDevice.current.systemVersion.replacingOccurrences(of: ".", with: "_")) like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1"
let url = URLRequest(url: URL(string: "https://mobile.twitter.com/i/flow/login")!)
webView.load(url)
}
これは見た目的にはいい感じになったのですが、
viewWillLayoutSubviews
は画面をちょっと動かすと何度でも呼ばれるっぽく、
その度に再読み込みが発生してまともに使えませんでした。
試したこと2
1で再読み込みが発生するのはviewWillLayoutSubviews
の中にwebView.load(url)
があるからだ!と思い、レイアウトが終わってすぐwebView.load(url)
をしようとしました。
override func viewWillLayoutSubviews() {
webView = WKWebView(frame: view.frame)
view.addSubview(webView)
}
override func viewDidAppear(_ animated: Bool) {
webView.customUserAgent = "Mozilla/5.0 (\(UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad"); CPU \(UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad") OS \(UIDevice.current.systemVersion.replacingOccurrences(of: ".", with: "_")) like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1"
let url = URLRequest(url: URL(string: "https://mobile.twitter.com/i/flow/login")!)
webView.load(url)
}
ライフサイクル表を見る限りこれは成功しそうです。
しかし、原因は分かりませんが、WebViewは真っ白で読み込みが行われませんでした。
おわり
おそらくこれは基本中の基本だと思いますが、大切だと思ったのでQiitaに残しておきます。
UIKit初心者は同じ問題にぶち当たると思うのでこの記事が役に立ては嬉しいです。