I have created a small project to replicate this problem.
The only file is this one...
Brief bit of code
class RootViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
showBlue()
}
@objc func showBlue() {
let vc = UIViewController()
vc.view.backgroundColor = .blue
let nvc = UINavigationController(rootViewController: vc)
vc.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(showGreen))
transition(to: nvc)
}
@objc func showGreen() {
let vc = UIViewController()
vc.view.backgroundColor = .green
let nvc = UINavigationController(rootViewController: vc)
vc.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(showBlue))
transition(to: nvc)
}
func transition(to toVC: UIViewController) {
if let fromVC = children.first {
transitionWithAnimation(fromVC: fromVC, toVC: toVC)
} else {
addWithoutAnimation(child: toVC)
}
}
func addWithoutAnimation(child toVC: UIViewController) {
addChild(toVC)
view.addSubview(toVC.view)
toVC.view.frame = view.bounds
toVC.didMove(toParent: self)
}
func transitionWithAnimation(fromVC: UIViewController, toVC: UIViewController) {
addChild(toVC)
toVC.view.frame = view.bounds
fromVC.willMove(toParent: nil)
transition(
from: fromVC,
to: toVC,
duration: 1.0,
options: .transitionCrossDissolve,
animations: nil) { _ in
fromVC.removeFromParent()
toVC.didMove(toParent: self)
}
}
}
Explaining the code
The RootViewController first does showBlue
. This adds a child UINavigationController
with a rootViewController
with a blue background. The blue view controller has a Done
button that then targets showGreen
.
showGreen
transitions to a UINavigationController
with a green background and a Done
button that targets showBlue
.
What I expected
What I expected (and what I want to happen) is for the navigation bar to cross dissolve in place without resizing.
Animation of the problem
The problem is that during the animated transition the navigation bar has a strange animation to it. Which you can see here...
Apple documentation around this
All the code is followed exactly from the Apple documentation about adding child view controllers to a custom container view controller... https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
Things I tried
I have also tried by using AutoLayout constraints rather than setting the view's frame directly but this didn't change anything.
I've tried running view.setNeedsLayout
and then view.layoutIfNeeded()
on the new view controller's view
but that doesn't seem to have fixed it either.
No strange animation if child is not UINavigationController
The really odd thing is that if you use any other type of view controller (other than UINavigationController
) then this animation glitch doesn't happen. For example: If one of the view controllers is a UITabBarController
then the tabs do not have this odd animation. Even stranger, if the tab contains a UINavigationController
then it doesn't have this animation either. It's literally just if the direct child is a UINavigationController
.
Has anyone experienced this before? And did you manage to stop the strange animation?