I am making a custom keyboard. I want to generate the keys'(UIButtons) width and height based on the view's width and height.
When the keyboard is loaded initially, viewDidAppear correctly determines the height of the view. (375 x 216)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.renderKeys()
}
When rotating to Landscape, it invokes viewWillTransition
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
NSLog("toSize \(size.width) x \(size.height)")
coordinator.animate(alongsideTransition: {(_ context: UIViewControllerTransitionCoordinatorContext) -> Void in
NSLog("animating \(self.view.frame.width) x \(self.view.frame.height)")
}, completion: {(_ context: UIViewControllerTransitionCoordinatorContext) -> Void in
NSLog("animationCompleted \(self.view.frame.width) x \(self.view.frame.height)")
self.renderKeys()
})
}
Rotating back to Portrait results this.
What I found is that viewWillTransition's to size isn't correctly determining the size that the view will be or I am just misunderstanding the usage of the function. Even after the animation, I am not able to get right width and height of the view.
Here is the debug log in order.
[28651:1348399] Calling viewDidAppear
[28651:1348399] Cleaning keys
[28651:1348399] toSize 667.0 x 216.0
[28651:1348399] animating 667.0 x 216.0
[28651:1348399] animationCompleted 667.0 x 216.0
[28651:1348399] Cleaning keys
[28651:1348399] toSize 375.0 x 162.0
[28651:1348399] animating 375.0 x 162.0
[28651:1348399] animationCompleted 375.0 x 162.0
I am working in a custom keyboard as well and found a similar problem.
After several hours experimenting, I have learned the following:
application(didFinishLaunchingWithOptions:)
,applicationDidBecomeActive
), etc are executed)viewWillTransition(to size:)
. e.g. in an iPhone 8+ this will report size of (414.0, 736.0) or (736.0, 414.0)Now, running the project as a Keyboard Target: -
application(didFinishLaunchingWithOptions:
),applicationDidBecomeActive
, etc. are not reportedViewController
is loaded.viewDidLoad
can be tricky, given that you may need a delay (usingTimer.scheduledTimer(withTimeInterval:)
, at least in the first iterationupdateViewConstraints()
, but the size seems to be not completely reliable. After each transition to Portrait, it can report the size to be 414 x 736 (ScreenSize) or 414 x 226 (correct keyboard size). In the case of an iPhone 8+viewWillTransition
method is not executed when going from Portrait to Landscape or from Landscape to Portrait (I guess this is related to the view life cycle that is interrupted in every rotation).So, What I am doing is to capture the screen size in
viewDidLoad
after a delay and forget aboutupdateViewConstraints
orviewWillTransition(to size:)
NOTE* This delay seems to be needed only in the first load (in this case, even
updateViewConstraints
is executed beforeviewDidLoad
. In following iterations of viewDidLoad, it is not required. Also. You may want to experiment the delay, and test in the actual devices vs. the simulatorReference table:
Device - (Screen) - (KeyboardPortrait) - (KeyboardLandscape)
iPhone X - (375 x 812) - (375 x 141) - (662 x 131)
iPhone 8+ - (414 x 736) - (414 x 226) - (736 x 162)
iPhone 7+/8+ - (414 x 736) - (414 x 226) - (736 x 162)
iPhone 7/8 - (375 x 667) - (375 x 216) - (667 x 162)
6/6s/6+/6s+ - Same as iPhone 7/8
iPhone SE - (320 x 568) - (320 x 216) - (568 x 162)
I hope it helps. Regards... e