5

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.

John Rogers
  • 2,192
  • 19
  • 29

3 Answers3

6

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/

Community
  • 1
  • 1
Siegfoult
  • 1,844
  • 17
  • 19
  • 1
    "Ghetto" doesn't even come close to describing this fix, but it works for me. – Thompson Sep 18 '14 at 18:13
  • As an alternative you could present it via segue and setup the transition delegate in prepareForSegue. This way the animation completed fine for me. – Razvan Pocaznoi May 29 '15 at 16:57
  • I've run into problems with this when your transition occurs after a view controller is presented. Calling dismissViewControllerAnimated: doesn't work probably because the views aren't where it expects them to be. – greg Oct 26 '15 at 00:48
  • Unfortunately this did not work for me, upon completion the background of toView is black, implying the presenting view controller is being removed. – mattyb Aug 08 '16 at 20:09
4

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.

arvinq
  • 656
  • 6
  • 12
  • this solves my issue also. Thanks! btw, do you know what is the reason? – soer May 07 '20 at 06:29
  • tbh, I am not sure.. haha i'm just as curious why its working when using a standard transition versus a custom one, I might have missed something.. but hey, if you found anything, let me know.. ^^ – arvinq May 07 '20 at 15:19
  • I found calling calling DispatchQueue.main.asyncAfter(deadline: .now()+1.0) { self?.navigationController?.present(nav, animated: true, completion: nil) } seems to solve it for me. – SmileBot Dec 16 '20 at 21:59
2

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)
    }
}
Andy Jacobs
  • 15,187
  • 13
  • 60
  • 91
  • 1
    Unfortunately this did not work for me, upon completion the background of toView is black, implying the presenting view controller is being removed. – mattyb Aug 08 '16 at 20:06
  • 2
    This solution worked fine for me, although I'm super suspicious that I'm still doing it 4 years on. – Andrew Plummer Jul 10 '18 at 02:46