How do I do a Fade/No transition between view controllers

前端 未结 10 742
时光取名叫无心
时光取名叫无心 2020-12-07 08:48

Is it possible to do a fade in and fade out transition between View Controllers in Storyboard. Or without transition.

If it\'s possible, what\'s the code for it?

相关标签:
10条回答
  • 2020-12-07 08:57

    This drove me absolutely nuts for several hours. None of these solutions seemed to be what I wanted, and I was losing my mind. Finally came up with the following, which swaps view controllers within a single NSWindow using a fade out/fade in transition. First it performs a fade out, then, in the completion handler, it sets the view for the window to the new view and performs a fade in. Maybe there's a better way to do this, but this is the simplest way I could hack together.

    class CustomSegue : NSStoryboardSegue {
        override func perform() {
            guard let fromController = sourceController as? NSViewController else {
                return;
            }
            guard let toController = destinationController as? NSViewController else {
                return;
            }
            let animationDuration = 0.5;
            NSAnimationContext.runAnimationGroup({
                $0.duration = animationDuration;
                fromController.view.animator().alphaValue = 0.0;
            }, completionHandler: {
                fromController.view.window?.contentViewController = toController;
                toController.view.alphaValue = 0.0;
                NSAnimationContext.runAnimationGroup({
                    $0.duration = animationDuration;
                    toController.view.animator().alphaValue = 1.0;
                })
            });
    
        }
    }
    

    The lack of examples in Apple documentation makes me want to tear my brain out, and the mix of Objective C and Swift everywhere is just... bah!

    0 讨论(0)
  • 2020-12-07 08:58

    If presenting a modal view controller, you can specify a modalTransitionStyle of UIModalTransitionStyleCrossDissolve. If doing this with a segue in your storyboard, select the attributes inspector for the segue, and specify the transition style there:

    enter image description here

    If presenting the view controller programmatically, you can define your modal segue between the view controllers in your storyboard with a "Transition" of "Cross Dissolve" and then have the source view controller perform this segue:

    [self performSegueWithIdentifier:@"presentSegue" sender:sender];
    

    Or, if you are calling presentViewController:

    UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"YourStoryboardID"];
    controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
    [self presentViewController:controller animated:YES completion:nil];
    

    In iOS 7, Apple has provided a new technology that provides a rich and robust control for highly customized transitions. For more information, refer to WWDC 2013 video Custom Transitions Using View Controllers.

    But, for instance, if you want to customize the push and pop animations in iOS 7 to fade, you would specify a delegate for the navigation controller

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

    You would then implement animationControllerForOperation that specified the animator objects for pushing and popping:

    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                      animationControllerForOperation:(UINavigationControllerOperation)operation
                                                   fromViewController:(UIViewController*)fromVC
                                                     toViewController:(UIViewController*)toVC
    {
        if (operation == UINavigationControllerOperationPush)
            return [[PushAnimator alloc] init];
    
        if (operation == UINavigationControllerOperationPop)
            return [[PopAnimator alloc] init];
    
        return nil;
    }
    

    You'd obviously have to implement your custom push and pop animators, such as:

    @interface PushAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    
    @end
    
    @implementation PushAnimator
    
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.5;
    }
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
        [[transitionContext containerView] addSubview:toViewController.view];
    
        toViewController.view.alpha = 0.0;
    
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            toViewController.view.alpha = 1.0;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
    }
    
    @end
    

    And

    @interface PopAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    
    @end
    
    @implementation PopAnimator
    
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.5;
    }
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    
        [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
    
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            fromViewController.view.alpha = 0.0;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
    }
    
    @end
    

    There is a similar, but slightly different technique for customizing modal transitions, too (though if you were just doing a face, you'd probably just use the modalTransitionStyle discussed above unless there was some other subtle customization you wanted to employ). See the aforementioned Custom Transitions Using View Controllers for more information.

    Bottom line, custom transitions for iOS 7 are a slightly complicated, but very robust way to provide tremendous control over the animations for transitions.

    0 讨论(0)
  • 2020-12-07 09:10

    Push/Pop UIVIewController FadeIn/FadeOut in Swift 3 syntax, based on Eugene Braginets's answer

    class FadeInPushSegue: UIStoryboardSegue {
    
        var animated: Bool = true
    
        override func perform() {
    
            let sourceViewController = self.source
            let destinationViewController = self.destination
    
            let transition: CATransition = CATransition()
    
            transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
            sourceViewController.view.window?.layer.add(transition, forKey: "kCATransition")
            sourceViewController.navigationController?.pushViewController(destinationViewController, animated: false)
    
        }
    
    }
    
    class FadeOutPopSegue: UIStoryboardSegue {
    
        override func perform() {
    
            let sourceViewController = self.source
    
            let transition: CATransition = CATransition()
    
            transition.duration = 0.4
            transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
            transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
    
            sourceViewController.view.window?.layer.add(transition, forKey: "kCATransition")
            _ = sourceViewController.navigationController?.popViewController(animated: false)
        }
    
    }
    
    0 讨论(0)
  • 2020-12-07 09:12

    What I did was to use Storyboard in Interface Builder, connected the two viewcontroller you need to move to /from and back (hold ctrl and drag click from the origin viewcontroller to destination viewcontroller), and changed the segue properties. I used the following:

    I then used the following:

    [self performSegueWithIdentifier:@"showMovieDetailSegue" sender:self];
    

    when you want to remove it, just call this from the origin viewcontroller:

    [self dismissViewControllerAnimated:YES completion:nil];
    

    Simple and very quick.

    0 讨论(0)
  • 2020-12-07 09:14

    For creating Custom Segue create subclass of UIStoryboard segue. For example:

    // MCFadeSegue.h
    #import <UIKit/UIKit.h>
    
    @interface MCFadeSegue : UIStoryboardSegue
    
    @end
    
    // MCFadeSegue.m
    #import <QuartzCore/QuartzCore.h>
    #import "MCFadeSegue.h"
    
    @implementation MCFadeSegue
    
    - (void)perform
    {
      CATransition *transition = [CATransition animation];
      transition.duration = 0.5;
      transition.type = kCATransitionFade;
    
      [[[[[self sourceViewController] view] window] layer] addAnimation:transition
          forKey:kCATransitionFade];
    
      [[self sourceViewController]
          presentViewController:[self destinationViewController]
          animated:NO completion:NULL];
    }
    
    @end
    

    Then in MainStoryboard.storyboard choose segue and set Style:Custom and Class:MCFadeSegue.

    0 讨论(0)
  • 2020-12-07 09:14

    Swift 5:

    After spending hours on finding the right solution Rob's one answered all of my needs, after a few adjustments it was perfect.

    Create the fade View Controller class:

    class FadeViewControllerTransition: NSObject, UIViewControllerAnimatedTransitioning {
        
        var fadeOut: Bool = false
        
        func transitionDuration(
            using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.5
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            
            if fadeOut {
                animateFadeOut(using: transitionContext)
                return
            }
            
            let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
            transitionContext.containerView.addSubview(toViewController.view)
            toViewController.view.alpha = 0.0
            UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
                toViewController.view.alpha = 1.0
            }, completion: { _ in
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
            })
        }
        
        func animateFadeOut(using transitionContext: UIViewControllerContextTransitioning) {
            
            let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
            let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
            transitionContext.containerView.insertSubview(toViewController.view, belowSubview: fromViewController.view)
            UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
                fromViewController.view.alpha = 0.0
            }, completion: { _ in
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
            })
        }
    }
    

    In your Navigation Controller's first View Controller:

    class MainViewController: UIViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {
    
        private let fadeVCTransition = FadeViewControllerTransition()
        
        func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            fadeVCTransition.fadeOut = (operation == .pop)
            return fadeVCTransition
        }
    

    And that's it.

    0 讨论(0)
提交回复
热议问题