I'm using custom transitions to display a fullscreen modal game view. When the user starts a game, the root view controller scales down "into" the screen, while the fullscreen game view controller zooms from a larger scale down onto the display while transitioning from 0% opacity to 100% opacity. Simple!
The transition looks great and works fine, also correctly reversing the animation when dismissing the game view controller.
The issue I'm having is that if the device is rotated while the fullscreen game view controller is displayed, on returning to the root view controller, the layout is all screwy. And further rotation doesn't fix the problem, the layout is screwy and stays screwy.
If I disable the use of a custom transition, this problem is gone. Also, if I keep the custom transition, but disable calls setting a CATransform3D on my source and destination views in the transition animation, the problem goes away again.
Here's my transitioning delegate:
class FullscreenModalTransitionManager: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate  {
    private var presenting:Bool = true
    // MARK: UIViewControllerAnimatedTransitioning protocol methods
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        // get reference to our fromView, toView and the container view that we should perform the transition in
        let container = transitionContext.containerView()
        let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
        let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
        let scale:CGFloat = 1.075
        //let bigScale = CGAffineTransformMakeScale(scale, scale)
        //let smallScale = CGAffineTransformMakeScale(1/scale,1/scale)
        let bigScale = CATransform3DMakeScale(scale, scale, 1)
        let smallScale = CATransform3DMakeScale(1/scale, 1/scale, 1)
        let smallOpacity:CGFloat = 0.5
        let presenting = self.presenting
        if presenting {
            // when presenting, incoming view must be on top
            container.addSubview(fromView)
            container.addSubview(toView)
            toView.layer.transform = bigScale
            toView.opaque = false
            toView.alpha = 0
            fromView.layer.transform = CATransform3DIdentity
            fromView.opaque = false
            fromView.alpha = 1
        } else {
            // when !presenting, outgoing view must be on top
            container.addSubview(toView)
            container.addSubview(fromView)
            toView.layer.transform = smallScale
            toView.opaque = false
            toView.alpha = smallOpacity
            fromView.layer.transform = CATransform3DIdentity
            fromView.opaque = false
            fromView.alpha = 1
        }
        let duration = self.transitionDuration(transitionContext)
        UIView.animateWithDuration(duration,
            delay: 0.0,
            usingSpringWithDamping: 0.7,
            initialSpringVelocity: 0,
            options: nil,
            animations: {
                if presenting {
                    fromView.layer.transform = smallScale
                    fromView.alpha = smallOpacity
                } else {
                    fromView.layer.transform = bigScale
                    fromView.alpha = 0
                }
            },
            completion: nil )
        UIView.animateWithDuration(duration,
            delay: duration/6,
            usingSpringWithDamping: 0.7,
            initialSpringVelocity: 0.5,
            options: nil,
            animations: {
                toView.layer.transform = CATransform3DIdentity
                toView.alpha = 1
            },
            completion: { finished in
                transitionContext.completeTransition(true)
            })
    }
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
        return 0.5
    }
    // MARK: UIViewControllerTransitioningDelegate protocol methods
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        self.presenting = true
        return self
    }
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        self.presenting = false
        return self
    }
}
And, for visual reference, here's what my root view controller normally looks like:

And, for visual reference, here's what my root view controller looks like if I rotate my device (at least once) while in the game view, and return to the root view controller.

And a final note - just in case it rings any bells - I'm using autolayout and size classes to lay out my root view controller.
Thanks,
I had a similar problem, I had written a custom transition for push and pop on a navigation controller. If you rotated the device after you did a push, when you popped back to the root view controller it's frame would be unchanged.
Problem

Solution
Objective C
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    // ViewController Reference
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    // Fix layout bug in iOS 9+
    toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];
    // The rest of your code ...
} 
Swift 3.0
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    // ViewController reference
    let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
    // Fix layout bug in iOS 9+
    toViewController.view.frame = transitionContext.finalFrame(for: toViewController)
    // The rest of your code ...
}
                        I accidentally figured this out, while doing some manual layout code on views with non-identity transforms. Turns out if your view has a non-identity transform, normal layout code fails.
The fix, in my transitioning delegate was to take the transited-out view, and in the animation complete callback set its transform to identity (since that view's invisible at the end of the animation, and behind the new view, this has no effect on the appearance)
UIView.animateWithDuration(duration,
    delay: 0.0,
    usingSpringWithDamping: 0.7,
    initialSpringVelocity: 0,
    options: nil,
    animations: {
        if presenting {
            fromView.transform = smallScale
            fromView.alpha = smallOpacity
        } else {
            fromView.transform = bigScale
            fromView.alpha = 0
        }
    },
    completion: { completed in
        // set transform of now hidden view to identity to prevent breakage during rotation
        fromView.transform = CGAffineTransformIdentity
    })
                        Finally I found solution for this issue. You need to improve @agilityvision code. You need to add BOOL value, something like closeVCNow that indicates you want to close VC, and in animateTransition:, in animation block do that:
if (self.closeVCNow) {
      toVC.view.transform = CGAffineTransformIdentity; 
      toVC.view.frame = [transitionContext finalFrameForViewController:toVC];
      self.closeVCNow = NO;
  }
                        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