Search code examples
iosobjective-canimationunwind-segue

iOS- How to disable animations in unwind segues programmatically?


I've created some unwind segues in XCode and by default they come with an animation which I don't want. After some searching around in Stack Overflow I did find that there is supposed to be a check box you can untick to disable animation, but that comes in Xcode 7 which I cannot upgrade to. How would I disable the unwind segue animation programmatically? I'm currently running XCode 6.4.


Solution

  • Let's name controller you are unwinding to FirstController and the one you are dismissing SecondController. Also there are two cases here: one when SecondController presented modally and one with UINavigationController involved.

    Unwind segue resets/ignores modalPresentationStyle, have to tweak it. In IBAction method called on FirstController upon unwinding add the following (I will assume you called this method prepareForUnwind):

    - (IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
        //TODO: add right condition if you have to
        UIViewController* secondController = (UIViewController*)segue.sourceViewController;
        secondController.transitioningDelegate = self;
        secondController.modalPresentationStyle = UIModalPresentationCustom;
    }
    

    This part will work when SecondController is dismissed from being modal. Now, for case when both controllers reside on UINavigationController, FirstController should become its delegate:

    - (void)viewDidLoad {
        self.navigationController.delegate = self;
    }
    

    This will make UIKit to ask FirstController for animator object for ensuing transitions. Now we should modify FirstController to return it.

    In FirstController.h:

    @interface FirstController : UIViewController<UIViewControllerTransitioningDelegate, UINavigationControllerDelegate>
    

    Add corresponding code to FirstController.m, so it would return some animator object for both cases (mind comments):

    - (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
    {
        return [Animator new];
    }
    
    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                      animationControllerForOperation:(UINavigationControllerOperation)operation
                                                   fromViewController:(UIViewController *)fromVC
                                                     toViewController:(UIViewController *)toVC {
        //This will disable ALL animations on particular UINavigationController
        //return nil to use default animation when appropriate
        return [Animator new];
    }
    

    Now implement Animator itself. It should confirm UIViewControllerAnimatedTransitioning protocol.

    In Animator.h:

    @interface Animator : NSObject<UIViewControllerAnimatedTransitioning>
    
    @end
    

    In Animator.m:

    @implementation Animator
    
    - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext {
        return 0;
    }
    
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
        UIViewController *controllerToDismiss = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIView *viewToDismiss = [transitionContext viewForKey:UITransitionContextFromViewKey];
        CGRect frameToDismissTo = [transitionContext finalFrameForViewController:controllerToDismiss];
        viewToDismiss.frame = frameToDismissTo;
    
        UIViewController *controllerToPresent = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        UIView *viewToPresent = [transitionContext viewForKey:UITransitionContextToViewKey];
        CGRect frameToPresentTo = [transitionContext finalFrameForViewController:controllerToPresent];
        viewToPresent.frame = frameToPresentTo;
    
        [[transitionContext containerView] addSubview:viewToPresent];
    
        [transitionContext completeTransition:YES];
    }
    
    @end
    

    Answer based on this post and this so answer (both not mine)