Reputation: 3671
I am trying to create a custom transition when popping or pushing ti my navigation controller. I have created a transitionManager class that conforms to the UINavigationControllerDelegate. I have created the object of this transitionManager and added it as a transitioningDelegate to my navigationController.
The push animation runs great but when I try to pop back to the previous viewController I only see a black screen.
I've ran through numerous other posts to make it work and tried everything at hand but it still doesn't show the previous ViewController when i pop.
The code for the transitionManager is here:
import UIKit
class BRTransitionManager: NSObject, UINavigationControllerDelegate, UIViewControllerAnimatedTransitioning {
private var presenting = true
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if operation == UINavigationControllerOperation.Push{
self.presenting = true
} else if operation == UINavigationControllerOperation.Pop{
self.presenting = false
}
return self
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView()
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
// set up from 2D transforms that we'll use in the animation
let offScreenRight = CGAffineTransformMakeTranslation(container.frame.width, 0)
let offScreenLeft = CGAffineTransformMakeTranslation(-container.frame.width, 0)
// prepare the toView for the animation
if (self.presenting == true) {
// add the both views to our view controller
container.addSubview(toView)
// container.addSubview(fromView)
toView.transform = offScreenRight
} else {
toView.transform = offScreenLeft
}
let duration = self.transitionDuration(transitionContext)
UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.8, options: nil, animations: {
if (self.presenting == true) {
fromView.transform = offScreenLeft
} else {
fromView.transform = offScreenRight
}
toView.transform = CGAffineTransformIdentity
}, completion: { finished in
transitionContext.completeTransition(true)
})
}
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 0.8
}
}
Upvotes: 0
Views: 3257
Reputation: 834
The UINavigationController maintains a weak reference to its delegate. If there is no strong reference then the UINavigationControllerDelegate object is deallocated once the transition is complete.
You can set the delegate object in Storyboard Editor. Add an object by dragging an object from the palette onto the Navigation Controller scene, between the First Responder and the Exit icons. Set its class to that of your delegate object. Make certain the module is your current application module. Then control-drag from the Navigation Controller icon to the object icon and choose "delegate" from the popup menu.
This seems to maintain a strong reference to the delegate object. The delegate object will then be available to invoke the unwind transition. You don't need to create the object yourself or set the delegate reference.
I found this technique in a blog post by Scott James Remnant.
Scott James Remnant - Custom iOS Segues, Transitions, and Animations - The Right Way
Upvotes: 1