iosswiftcocoauikeyboardscreen-rotation

changing height of a custom keyboard when rotating


I have a customized keyboard created by code, it is a unique input view for a specific textfield. I implement this in my project:

let keyboardContainerView = KBContainerView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height*0.5))
keyboardContainerView.addSubview(myKeyboardView)
textfield.inputView = keyboardContainerView

The KBContainerView is a UIView but has a function, that is when detected device rotation, the frame change. It's quite simple.

override init(frame: CGRect) {
    super.init(frame: frame)
    NotificationCenter.default.addObserver(self, selector: #selector(updateFrame), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}
    
@objc func updateFrame() {
    self.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height*0.5)
}

But I found that though the keyboard container view is changed, as I printed it on the command line but the size of keyboard seems does not change. Here is a gif.

Portrait

Start from a landscape view does not change the height either.

Landscape

To fix this problem I tried to use autoresizingMasks on the input view but things get worse, the keyboard height is wrong when starts the app. The navigation bar also covered keyboard in landscapeview.

Adding the autoresizingMasks

In my project, I did not wrote a UIKeyboardviewController for simplicity. What I am trying to achieve is that when rotating my device, the keyboard can takes half space of the screen. (height is 0.5 * screen height)

Is it because I wrote the change size action in the wrong place?


Solution

  • Usually I get use the standard keyboard dimensions for my custom inputView using

    autoresizingMask = [.flexibleWidth, .flexibleHeight]
    

    In this case, if you want it always to be 50% of the height, you might want to

    For example, below is a simple input view that I've defined to be 50% of the height of the window with the following within the keyboard input UIView subclass:

    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        
        translatesAutoresizingMaskIntoConstraints = false
    
        guard let superview = superview else { return }
        
        var lastView: UIView! = self
        while lastView.superview != nil {
            lastView = lastView.superview
        }
    
        NSLayoutConstraint.activate([
            heightAnchor.constraint(equalTo: lastView.heightAnchor, multiplier: 0.5, constant: 0),
            widthAnchor.constraint(equalTo: superview.widthAnchor),
            centerXAnchor.constraint(equalTo: superview.centerXAnchor),
            bottomAnchor.constraint(equalTo: superview.bottomAnchor)
        ])
    }
    

    Now I'm crawling up the view hierarchy to get the top level view. Perhaps you'd want to pass it the view that you want it to use for the height constraint. I just hate referring to UIScreen.main because sometimes our app won't have the full screen.

    But let's not get lost in the details. The key is to use constraints and let the auto layout engine do everything for us. Then we don't have to respond to rotation events ourselves:

    enter image description here