简体   繁体   中英

Is there a way to tell iOS to update the keyboard appearance within a view controller?

I'd like to update the UIKeyboardAppearance within a ViewController . By this I mean let's say the VC loads with UIKeyboardAppearance.default . If I press a button, I'd like the keyboard to update to .dark and have the keyboard now show in that same VC as .dark .

As far as I can tell, iOS checks the value for UIKeyboardAppearance while loading the VC, and doesn't check again until it loads the VC again. Even if you change the value of UIKeyboardAppearance and hide/show the keyboard.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

// creating a simple text box, and making the placeholder text the value of the keyboardAppearance
        myTextBox.backgroundColor = UIColor.lightGray
        myTextBox.frame = CGRect(x: 30, y: 200, width: 300, height: 50)
        view.addSubview(myTextBox)
        UITextField.appearance().keyboardAppearance = .dark
        myTextBox.becomeFirstResponder()
        myTextBox.placeholder = "Keybaoard Appearance is: \(UITextField.appearance().keyboardAppearance.rawValue)"

// a simple button to toggle the keyboardAppearance
        toggleButton.frame = CGRect(x: 30, y: 300, width: 300, height: 50)
        toggleButton.setTitle("Toggle Keyboard", for: .normal)
        toggleButton.backgroundColor = UIColor.red
        toggleButton.addTarget(self, action: #selector(toggleButtonFunction), for: .touchUpInside)
        view.addSubview(toggleButton)

    }

// toggles the keyboardAppearance. Hides the keyboard, and a second later shows it again.
    @objc func toggleButtonFunction() {
        if UITextField.appearance().keyboardAppearance == .dark {
            UITextField.appearance().keyboardAppearance = .default
        }
        else {
            UITextField.appearance().keyboardAppearance = .dark
        }
        myTextBox.resignFirstResponder()
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
            self.myTextBox.becomeFirstResponder()
            self.myTextBox.placeholder = "Keybaoard Appearance is: \(UITextField.appearance().keyboardAppearance.rawValue)"

            })
    }

    let myTextBox = UITextField()
    let toggleButton = UIButton()
}

I was hoping that after changing the UIKeyboardAppearance and hiding/showing the keyboard it would show with the new appearance ( .dark or .default ), but it continually shows with the same appearance until the VC is loaded again. You can see the value of UIKeyboardAppearance changes, but iOS seems to not check for that update until the VC loads again.

Is there any way to force a recheck within a VC?

Thanks for your help!

You can change the keyboard appearance of all text fields recursively on your screen (the allSubviewsOf(type:) extension is from this great answer by Mohammad Sadiq ):

func changeTextFieldKeyboardAppearance() {
    UITextField.appearance().keyboardAppearance = .dark

    let textFields = view.allSubviewsOf(type: UITextField.self)

    let firstResponder = textFields.first { $0.isFirstResponder }

    firstResponder?.resignFirstResponder()

    textFields.forEach { $0.keyboardAppearance = .dark }

    firstResponder?.becomeFirstResponder()
}

[...]

extension UIView {
    func allSubviewsOf<T: UIView>(type: T.Type) -> [T] {
        var all = [T]()

        func getSubview(view: UIView) {
            if let aView = view as? T {
                all.append(aView)
            }

            guard !view.subviews.isEmpty else {
                return
            }

            view.subviews.forEach{ getSubview(view: $0) }
        }

        getSubview(view: self)

        return all
    }
}

If your view controller is embedded in a UITabBarController , you can trigger an update by changing its selectedIndex and changing it back to the original index immediately:

guard let tabBarController = tabBarController else {
    return
}

let selectedIndex = tabBarController.selectedIndex

UITextField.appearance().keyboardAppearance = .dark

tabBarController.selectedIndex = selectedIndex == 1 ? 0 : 1
tabBarController.selectedIndex = selectedIndex

Thanks to Tamás for the answer!

It led me down the path to discover what I needed.

It looks like if you change the keyboardAppearance for UITextField

UITextField.appearance().keyboardAppearance = .dark

the system only checks on VC load. If you change it for each textField

myTextBox.keyboardAppearance = .dark

the system will check each time firstResponder changes and load the correct keyboard.

Thanks again Tamás!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM