I have a custom UIStoryboardSegue that works as desired in iOS12.*.
One of the destination view controller is a UITabbarController: for each tab, I have a controller embedded in a navigation controller.
Unfortunately, for iOS13.*, this does not work well: the view controller lifecycle is broken, and no call the viewXXXAppear() nor the willTransition() methods are no longer issued.
It looks like makeKeyAndVisible() has no effect?!
See at the bottom how the screen UI is puzzled below without viewWillAppear() being called.
An horrible temporary workaround
I had to pull my hairs but, I have found a fix which I make public (I had to add a navigation controller on the fly).
This messes the vc hierarchy: do you have a better solution?
public class AladdinReplaceRootViewControllerSegue: UIStoryboardSegue {
override public func perform() {
guard let window = UIApplication.shared.delegate?.window as? UIWindow,
let sourceView = source.view,
let destinationView = destination.view else {
super.perform()
return
}
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
destinationView.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
window.insertSubview(destinationView, aboveSubview: sourceView)
// **My fix**
if #available(iOS 13,*) {
// I introduced an invisible navigation controller starting in iOS13 otherwise, my controller attached to the tabbar thru a navigation, dont work correctly, no viewXAppearis called.
let navigationController = UINavigationController.init(rootViewController: self.destination)
navigationController.isNavigationBarHidden = true
window.rootViewController = navigationController
}
else {
window.rootViewController = self.destination
}
window.makeKeyAndVisible()
}
}
I found a solution thanks to Unbalanced calls to begin/end appearance transitions with custom segue What happens here is that the creation and attaching of the destination view controller happens twice, and the first one happens too soon. So what you need to do is:
public class AladdinReplaceRootViewControllerSegue: UIStoryboardSegue {
override public func perform() {
guard let window = UIApplication.shared.delegate?.window as? UIWindow,
let sourceView = source.view,
let destinationView = destination.view else {
super.perform()
return
}
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
let mock = createMockView(view: desination.view)
window.insertSubview(mock, aboveSubview: sourceView)
//DO SOME ANIMATION HERE< MIGHT NEED TO DO mock.alpha = 0
//after the animation is done:
window.rootViewController = self.destination
mock.removeFromSuperview()
}
func createMockView(view: UIView) -> UIImageView {
UIGraphicsBeginImageContextWithOptions(view.frame.size, true, UIScreen.main.scale)
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return UIImageView(image: image)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With