iOS Custom Keyboard Extension - Change height to fullscreen

Viewed 151

I have an iOS Custom Keyboard Extension (UIInputViewController) and I want to make it fullscreen.

Changing its height is pretty straightforward:

self.heightConstraint = NSLayoutConstraint(item: self.view!,
                                                   attribute: NSLayoutConstraint.Attribute.height,
                                                   relatedBy: NSLayoutConstraint.Relation.equal,
                                                   toItem: nil,
                                                   attribute: NSLayoutConstraint.Attribute.notAnAttribute,
                                                   multiplier: 0,
                                                   constant: UIScreen.main.bounds.height)

The problem is that the keyboard's frame is placed on top of the UIKeyboardDockView -- the bottom area that contains the globe (change keyboard) and the mic (dictation) icon.

Now, I want to get access to that bottom area so that I can subtract its height to UIScreen.main.bounds.height.

Does anyone know if it's possible? If not, please feel free to suggest any other solution.

Xcode UI debugger view Simulator screenshot

1 Answers

This is working for me. It looks like calling view.layoutIfNeeded() inside viewWillAppear is important.

import UIKit

class InputVC: UIInputViewController {
    
    var initialHeightConstraint: NSLayoutConstraint?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        guard let view = view else { return }
        
        view.backgroundColor = .red
        
        view.translatesAutoresizingMaskIntoConstraints = false
        
        self.initialHeightConstraint = NSLayoutConstraint(item: view, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: UIScreen.main.bounds.height)
        self.initialHeightConstraint?.isActive = true
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        view.layoutIfNeeded()
    }
}

class ViewController: UIViewController {
    
    var inputVC = InputVC()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .green
    }
    
    override var canBecomeFirstResponder: Bool {
        true
    }
    
    override var inputAccessoryViewController: UIInputViewController? {
        inputVC
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        becomeFirstResponder()
    }
}

I also tried pinning it to the window in a few spots, which also worked, but gave me constraint errors in the console.

override func didMove(toParent parent: UIViewController?) {
    super.didMove(toParent: parent)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    guard let view = view, let window = view.window else { return }

    self.initialHeightConstraint?.isActive = false
    
    NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: window, attribute: .top, multiplier: 1, constant: 0).isActive = true
    
    NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal, toItem: window, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
    
    NSLayoutConstraint(item: view, attribute: .left, relatedBy: .equal, toItem: window, attribute: .left, multiplier: 1, constant: 0).isActive = true

    NSLayoutConstraint(item: view, attribute: .right, relatedBy: .equal, toItem: window, attribute: .right, multiplier: 1, constant: 0).isActive = true

    self.view.layoutIfNeeded()
}
Related