LoginSignup
0
1

More than 1 year has passed since last update.

【Swift】WKWebViewでキーボードを開くとレイアウトエラーが発生する

Last updated at Posted at 2022-08-25

はじめに

以前からWKWebViewではキーボード関係でレイアウトエラーが発生していましたが、ログ上のエラーだけで見た目には影響はありませんでした。
しかし、今回キーボード関係で見た目に不具合が起きたので原因と解決方法を紹介します。

症状1

キーボードを開いて閉じるとキーボードがあった場所に空白ができる
Simulator Screen Recording - iPhone 12 - 2022-08-24 at 21.49.39.gif

症状2

最初からテキストフィールドにフォーカスされる画面だと上に画面が圧縮されている
Simulator Screen Recording - iPhone 12 - 2022-08-24 at 21.55.23.gif

現在のコード

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から使っていることでした。
@StateisLoginWebViewを使えば正常に動作しました。

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)
            }
        }
    }
}

おわり

なぜこんな事が起きているのかは分かりませんがとりあえず直せてよかったです。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1