Reputation: 41
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.
Start from a landscape view does not change the height either.
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.
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?
Upvotes: 2
Views: 718
Reputation: 48
In my case, using stack views to build up the entire numeric keypad as a custom InputView for text fields.
So the solution is to set stack view's size as orientation changes in layoutSubviews() and update intrinsicContentSize accordingly
override func layoutSubviews() {
super.layoutSubviews()
mainStackView.frame.size = CGSize(width: bounds.width, height: <dynamicHeight>)
}
override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: <dynamicHeight>)
}
Ensure you've set autoresizingMask for your custom inputView and mainStackView
autoresizingMask = [.flexibleWidth, .flexibleHeight]
I have created an extension to detect whether current orientation is Portrait of Landscape:
extension UIDevice {
var isLandscapeMode: Bool {
return (UIDevice.current.orientation == .landscapeLeft) || (UIDevice.current.orientation == .landscapeRight) || (UIScreen.main.bounds.width > UIScreen.main.bounds.height)
}
}
Leaving my comment here in case someone needs it
Upvotes: 0
Reputation: 438232
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
translatesAutoresizingMaskIntoConstraints
;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:
Upvotes: 3