Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Presented view controller disappears after animation using custom UIViewController animations

I've looked around for an answer for this and spent the last two hours pulling my hair out to no end.

I'm implementing a very basic custom view controller transition animation, which simply zooms in on the presenting view controller and grows in the presented view controller. It adds a fade effect (0 to 1 alpha and visa versa).

It works fine when presenting the view controller, however when dismissing, it brings the presenting view controller back in all the way to fill the screen, but then it inexplicably disappears. I'm not doing anything after these animations to alter the alpha or the hidden values, it's pretty much a fresh project. I've been developing iOS applications for 3 years so I suspect this may be a bug, unless someone can find out where I'm going wrong.

class FadeAndGrowAnimationController : NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
func animationControllerForPresentedController(presented: UIViewController!, presentingController presenting: UIViewController!, sourceController source: UIViewController!) -> UIViewControllerAnimatedTransitioning! {
    return self
}

func animationControllerForDismissedController(dismissed: UIViewController!) -> UIViewControllerAnimatedTransitioning! {
    return self
}

func transitionDuration(transitionContext: UIViewControllerContextTransitioning!) -> NSTimeInterval {
    return 2
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning!) {
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as UIViewController
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as UIViewController

    toViewController.view.transform = CGAffineTransformMakeScale(0.5, 0.5)
    toViewController.view.alpha = 0

    transitionContext.containerView().addSubview(fromViewController.view)
    transitionContext.containerView().addSubview(toViewController.view)
    transitionContext.containerView().bringSubviewToFront(toViewController.view)

    UIView.animateWithDuration(self.transitionDuration(transitionContext), animations: {
        fromViewController.view.transform = CGAffineTransformScale(fromViewController.view.transform, 2, 2)
        fromViewController.view.alpha = 1

        toViewController.view.transform = CGAffineTransformMakeScale(1, 1)
        toViewController.view.alpha = 1
    }, completion: { finished in
        transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    })
}

}

And the code to present:

    let targetViewController = self.storyboard.instantiateViewControllerWithIdentifier("Level1ViewController") as Level1ViewController
    let td = FadeAndGrowAnimationController()

    targetViewController.transitioningDelegate = td
    targetViewController.modalPresentationStyle = .Custom

    self.presentViewController(targetViewController, animated: true, completion: nil)

As you can see, a fairly basic animation. Am I missing something here? Like I said, it presents perfectly fine, then dismisses 99.99% perfectly fine, yet the view controller underneath after the dismissal is inexplicably removed. The iPad shows a blank screen - totally black - after this happens.

like image 857
John Rogers Avatar asked Sep 02 '14 07:09

John Rogers


People also ask

How to create a custom dismiss animation controller in uiviewcontrollertransitioningdelegate?

The UIViewControllerTransitioningDelegate also allows you to specify an animation controller to use when dismissing a view controller as well as when presenting one. We’ll create this next. Create a class named CustomDismissAnimationController that is a subclass of NSObject. Modify its declaration as shown. Add the following to the class.

Can a controller animate its own view?

For example, a presented view controller might animate its own view hierarchy during the transition and add motion effects or other visual feedback while the transition occurs. Any object can create animations, as long as it is able to access the transitionCoordinator property of the presented or presenting view controller.

How do I use a custom transition in UIViewController?

UIViewController has a property named transitionDelegate that supports custom transitions. When transitioning to a view controller, the framework checks this property to see if a custom transition should be used. UIViewControllerTransitioningDelegate supplies custom transitions.

What is interactive animator object in UIView?

Interactive animator objects. An interactive animator object drives the timing of custom animations using touch events or gesture recognizers. Interactive animator objects conform to the UIViewControllerInteractiveTransitioning protocol.


3 Answers

I was having the same problem when dismissing a content view controller. My app has this parent view controller showing a child view controller. then when a subview in the child is tapped, it shows another vc (which I am calling the content vc)

My problem is that, when dismissing the contentVC, it should go to child VC but as soon as my custom transition finishes, childVC suddenly disappears, showing the parent VC instead.

What I did to solve this issue is to

  1. change the .modalPresentationStyle of the childVC presented by parentVC from the default .automatic to .fullscreen.
  2. Then changed the .modalPresentationStyle of contentVC to .fullscreen as well.

This solves the issue. but it won't show your child VC as a card sheet (when using .overCurrentContext or automatic) which is new in iOS 13.

like image 26
arvinq Avatar answered Oct 19 '22 17:10

arvinq


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/

like image 135
Siegfoult Avatar answered Oct 19 '22 18:10

Siegfoult


had the same problem ios 8.1

my swift code after completeTransition

if let window = UIApplication.sharedApplication().keyWindow {
    if let viewController = window.rootViewController {
        window.addSubview(viewController.view)
    }
}
like image 27
Andy Jacobs Avatar answered Oct 19 '22 17:10

Andy Jacobs