How to change the Push and Pop animations in a navigation based app

前端 未结 25 1413
清酒与你
清酒与你 2020-11-22 12:46

I have a navigation based application and I want to change the animation of the push and pop animations. How would I do that?

Edit 2018

Ther

25条回答
  •  無奈伤痛
    2020-11-22 13:05

    How to change the Push and Pop animations in a navigation based app...

    For 2019, the "final answer!"

    Preamble:

    Say you are new to iOS development. Confusingly, Apple provide two transitions which can be used easily. These are: "crossfade" and "flip".

    But of course, "crossfade" and "flip" are useless. They are never used. Nobody knows why Apple provided those two useless transitions!

    So:

    Say you want to do an ordinary, common, transition such as "slide". In that case, you have to do a HUGE amount of work!.

    That work, is explained in this post.

    Just to repeat:

    Surprisingly: with iOS, if you want the simplest, most common, everyday transitions (such as an ordinary slide), you do have to all the work of implementing a full custom transition.

    Here's how to do it ...

    1. You need a custom UIViewControllerAnimatedTransitioning

    1. You need a bool of your own like popStyle . (Is it popping on, or popping off?)

    2. You must include transitionDuration (trivial) and the main call, animateTransition

    3. In fact you must write two different routines for inside animateTransition. One for the push, and one for the pop. Probably name them animatePush and animatePop. Inside animateTransition, just branch on popStyle to the two routines

    4. The example below does a simple move-over/move-off

    5. In your animatePush and animatePop routines. You must get the "from view" and the "to view". (How to do that, is shown in the code example.)

    6. and you must addSubview for the new "to" view.

    7. and you must call completeTransition at the end of your anime

    So ..

      class SimpleOver: NSObject, UIViewControllerAnimatedTransitioning {
            
            var popStyle: Bool = false
            
            func transitionDuration(
                using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
                return 0.20
            }
            
            func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
                
                if popStyle {
                    
                    animatePop(using: transitionContext)
                    return
                }
                
                let fz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
                let tz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
                
                let f = transitionContext.finalFrame(for: tz)
                
                let fOff = f.offsetBy(dx: f.width, dy: 55)
                tz.view.frame = fOff
                
                transitionContext.containerView.insertSubview(tz.view, aboveSubview: fz.view)
                
                UIView.animate(
                    withDuration: transitionDuration(using: transitionContext),
                    animations: {
                        tz.view.frame = f
                }, completion: {_ in 
                        transitionContext.completeTransition(true)
                })
            }
            
            func animatePop(using transitionContext: UIViewControllerContextTransitioning) {
                
                let fz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
                let tz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
                
                let f = transitionContext.initialFrame(for: fz)
                let fOffPop = f.offsetBy(dx: f.width, dy: 55)
                
                transitionContext.containerView.insertSubview(tz.view, belowSubview: fz.view)
                
                UIView.animate(
                    withDuration: transitionDuration(using: transitionContext),
                    animations: {
                        fz.view.frame = fOffPop
                }, completion: {_ in 
                        transitionContext.completeTransition(true)
                })
            }
        }
    

    And then ...

    2. Use it in your view controller.

    Note: strangely, you only have to do this in the "first" view controller. (The one which is "underneath".)

    With the one that you pop on top, do nothing. Easy.

    So your class...

    class SomeScreen: UIViewController {
    }
    

    becomes...

    class FrontScreen: UIViewController,
            UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {
        
        let simpleOver = SimpleOver()
        
    
        override func viewDidLoad() {
            
            super.viewDidLoad()
            navigationController?.delegate = self
        }
    
        func navigationController(
            _ navigationController: UINavigationController,
            animationControllerFor operation: UINavigationControllerOperation,
            from fromVC: UIViewController,
            to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            
            simpleOver.popStyle = (operation == .pop)
            return simpleOver
        }
    }
    

    That's it.

    Push and pop exactly as normal, no change. To push ...

    let n = UIStoryboard(name: "nextScreenStoryboardName", bundle: nil)
              .instantiateViewController(withIdentifier: "nextScreenStoryboardID")
              as! NextScreen
    navigationController?.pushViewController(n, animated: true)
    

    and to pop it, you can if you like just do that on the next screen:

    class NextScreen: TotallyOrdinaryUIViewController {
        
        @IBAction func userClickedBackOrDismissOrSomethingLikeThat() {
            
            navigationController?.popViewController(animated: true)
        }
    }
    

    Phew.


    3. Also enjoy the other answers on this page which explain how to override AnimatedTransitioning

    Scroll to @AlanZeino and @elias answer for more discussion on how to AnimatedTransitioning in iOS apps these days!

提交回复
热议问题