はじめに
以前からWKWebViewではキーボード関係でレイアウトエラーが発生していましたが、ログ上のエラーだけで見た目には影響はありませんでした。
しかし、今回キーボード関係で見た目に不具合が起きたので原因と解決方法を紹介します。
症状1
キーボードを開いて閉じるとキーボードがあった場所に空白ができる
症状2
最初からテキストフィールドにフォーカスされる画面だと上に画面が圧縮されている
現在のコード
import SwiftUI
struct ContentView: View {
@StateObject private var loginViewModel = LoginViewModel()
var body: some View {
GeometryReader { geo in
VStack(alignment: .center, spacing: 15) {
Button("ログイン") {
loginViewModel.isLoginWebView = true
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.scaleEffect(geo.size.width > 450 ? 1.5 : 1.0)
.sheet(isPresented: $loginViewModel.isLoginWebView) {
LoginWebView(loginViewModel: loginViewModel)
}
}
}
}
import UIKit
import WebKit
import SwiftUI
struct LoginWebView: UIViewControllerRepresentable {
@ObservedObject var loginViewModel: LoginViewModel
func makeUIViewController(context: Context) -> WebViewController {
return WebViewController(loginViewModel: loginViewModel)
}
func updateUIViewController(_ uiViewController: WebViewController, context: Context) { }
}
class WebViewController: UIViewController {
var loginViewModel: LoginViewModel
init(loginViewModel: LoginViewModel) {
self.loginViewModel = loginViewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
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: .zero)
webView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(webView)
webView.customUserAgent = "Mozilla/5.0 (iPhone); CPU iPhone OS 15_5 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
class LoginViewModel: NSObject, ObservableObject {
@Published public var isLoginWebView: Bool = false
}
修正方法1
ContentViewに付けている.scaleEffect(geo.size.width > 450 ? 1.5 : 1.0)
です。
これを削除すれば修正できました。
しかし、iPadの時はちょっとViewを大きくしたいので、これは削除したくありません。
import SwiftUI
struct ContentView: View {
@StateObject private var loginViewModel = LoginViewModel()
var body: some View {
GeometryReader { geo in
VStack(alignment: .center, spacing: 15) {
Button("ログイン") {
loginViewModel.isLoginWebView = true
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
- .scaleEffect(geo.size.width > 450 ? 1.5 : 1.0)
.sheet(isPresented: $loginViewModel.isLoginWebView) {
LoginWebView(loginViewModel: loginViewModel)
}
}
}
}
修正方法2
isLoginWebView
をViewModelから使っていることでした。
@State
でisLoginWebView
を使えば正常に動作しました。
import SwiftUI
struct ContentView: View {
- @StateObject private var loginViewModel = LoginViewModel()
+ @State private var isLoginWebView: Bool = false
var body: some View {
GeometryReader { geo in
VStack(alignment: .center, spacing: 15) {
Button("ログイン") {
- loginViewModel.isLoginWebView = true
+ isLoginWebView = true
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.scaleEffect(geo.size.width > 450 ? 1.5 : 1.0)
- .sheet(isPresented: $loginViewModel.isLoginWebView) {
+ .sheet(isPresented: $isLoginWebView) {
LoginWebView(loginViewModel: loginViewModel)
}
}
}
}
おわり
なぜこんな事が起きているのかは分かりませんがとりあえず直せてよかったです。