From View Controller disappears using UIViewControllerContextTransitioning
I was having the same problem here – looks like a bug in iOS 8. I've filed a radar.
I used Reveal to inspect the view hierarchy after the screen goes black. The key UIWindow
is completely empty – no view hierarchy at all!
I played around a bit and it looks like there is an easy workaround, for simple cases. You can just re-add the toViewController
's view as a subview of the key window's:
transitionContext.completeTransition(true)
UIApplication.sharedApplication().keyWindow!.addSubview(toViewController.view)
I've checked and the key window's rootViewController
is still correctly set, so that's fine. I'm not sure what would happen if you presented your controller from within an already presented modal controller, so for more complex cases, you'll have to experiment around.
UIViewController interactive transition - Presented view disappears when interactive dismiss is canceled
Thanks to a comment by @Dare, I realized all that was needed was a small update to the dismiss animation completion block:
// before - broken
transitionContext.completeTransition(true)
// after - WORKING!
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
How do I keep the source view controller from disappearing after a push segue?
I suggest you create a custom transition between view controllers.
I just wrote and tested this class:
class AnimationController: NSObject, UIViewControllerAnimatedTransitioning
{
var pushing = true
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let duration = transitionDuration(using: transitionContext)
let toVc = transitionContext.viewController(forKey: .to)!
let toView = transitionContext.view(forKey: .to)!
let fromView = transitionContext.view(forKey: .from)!
let container = transitionContext.containerView
if pushing {
container.addSubview(fromView)
container.addSubview(toView)
}
var finalFrame = transitionContext.finalFrame(for: toVc)
if pushing {
finalFrame.origin.x = finalFrame.width
toView.frame = finalFrame
finalFrame.origin.x = 0
} else {
finalFrame.origin.x = finalFrame.width
}
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
if self.pushing {
toView.frame = finalFrame
} else {
fromView.frame = finalFrame
}
}) { (_) in
transitionContext.completeTransition(true)
if self.pushing {
container.insertSubview(fromView, belowSubview: toView)
} else {
fromView.removeFromSuperview()
}
}
}
}
In your UINavigationController
class do the following:
class NavigationController: UINavigationController {
let animationController = AnimationController()
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
}
And this extension:
extension NavigationController: UINavigationControllerDelegate
{
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
animationController.pushing = operation == .push
return animationController
}
}
However, this makes you lose the interactive dismiss gesture (Swiping from the left of the screen to dismiss) So you would need to fix that yourself.
Container view disappearing on completeTransition:
The container view disappearing on dismissal is correct behavior. Your mistake is adding the fromView
to it.
You are incorrectly distinguishing whether this is presentation or dismissal and what you should do in each case. Simply use the two view controllers fromViewController
and toViewController
to tell them apart; on dismissal, the roles are reversed. On dismissal, do not add anything to the content view; the original presenter is still present and will be revealed by the removal of the container view.
So, on presentation, add only the toView
to the container view. On dismissal, do not add anything to the container view. It's as simple as that.
Presented view controller disappears after animation using custom UIViewController animations
This seems to be an iOS8 bug. I found a solution but it is ghetto. After the transition when a view should be on-screen but isn't, it needs to be added back to the window like this:
BOOL canceled = [transitionContext transitionWasCancelled];
[transitionContext completeTransition:!canceled];
if (!canceled)
{
[[UIApplication sharedApplication].keyWindow addSubview: toViewController.view];
}
You might need to play around with which view you add back to the window, whether to do it in canceled or !canceled, and perhaps making sure to only do it on dismissal and not presentation.
Sources: Container view disappearing on completeTransition:
http://joystate.wordpress.com/2014/09/02/ios8-and-custom-uiviewcontrollers-transitions/
Does a view controller get removed entirely when using a custom transition?
You said:
is my view controller still get removed after the transition finishes or is it still there but off the screen?
There are two completely separate issues here.
First, there is a question of the view controller hierarchy. When you present a new view controller, the old view controller is always kept in the view controller hierarchy so that when you dismiss back to it, it will still be there. However, when you dismiss, the dismissed view controller will be removed from the view controller hierarchy and (unless you do something unusual, like keeping your own strong reference to it somewhere) it will be deallocated.
Second, there is a separate question of the view hierarchy. When presenting, the UIPresentationController
dictates whether the presenting view controller's view remains in the view hierarchy or not. By default, it keeps it in the view hierarchy, but generally if doing a modal, full-screen "present", you'd specify a UIPresentationController
subclass that tells it to remove the presenting view controller's view when the transition is done.
For example, when doing a custom modal "present" transition where the presented view controller's view is opaque and covers the whole screen, then your UIViewControllerTransitioningDelegate
would not only supply the animation controllers, but also specify a presentation controller:
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return YourAnimationController(...)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return YourAnimationController(...)
}
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return PresentationController(presentedViewController: presented, presenting: presenting)
}
And that presentation controller might be fairly minimal, only telling it to remove the presenter's view:
class PresentationController: UIPresentationController {
override var shouldRemovePresentersView: Bool { return true }
}
UIViewController custom transition stuck on iOS13
Ok, it was easy, even though, it's a breaking API change of Apple.
viewController.modalPresentationStyle = .fullScreen
Now I have to go through my whole project and check all modal presentations if they still look as I need them to.
Related Topics
Sorting Nsarray of Dictionaries by Value of a Key in the Dictionaries
Ibeacon: Didrangebeacons Stops Getting Called, Must Reset Device for It to Work Again
iOS 7 App Icons, Launch Images and Naming Convention While Keeping iOS 6 Icons
How to Add Unique Constraints for Some Fields in Core Data
How to Create an Umbrella Framework in iOS Sdk
Nsxmlparser on iOS, How to Use It Given a Xml File
Determine If the Access to Photo Library Is Set or Not - PHPhotolibrary
Xmppframework - Implement Group Chat (Muc)
Ios: Sample Code for Simultaneous Record and Playback
How to Apply Uiappearance Proxy Properties to Uilabel
What Is the Height of Iphone's Onscreen Keyboard
Nsurlconnection Sendasynchronousrequest Can't Get Variable Out of Closure
Uilabel Layer Cornerradius Negatively Impacting Performance
How to Make an Uipickerview Component Wrap Around
Custom Init for Uiviewcontroller in Swift with Interface Setup in Storyboard
How to Overload an Assignment Operator in Swift