UINavigationController内的页面跳转实现 UIViewController 的 present和dismiss竖直方向动画

UINavigationController内部页面跳转默认为左右切换,但是当我们想向上弹出进入界面,或者向下离开界面时,需要实现UINavigationControllerDelegate 协议自行控制页面的动画(否则直接在navVc上叠加动画会导致动画结束后的那个页面,自动加了异常动画),本文介绍这个实现方案。

定义一个类实现 UIViewControllerAnimatedTransitioning协议,实现下面的函数:


class NavigationControllerAnimation: NSObject, UIViewControllerAnimatedTransitioning {

    let operation: UINavigationController.Operation
    
    init(operation: UINavigationController.Operation) {
        self.operation = operation

        super.init()
    }
    //页面过渡动画时间 
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.3
    }
    
    //加页面过渡的动画
    public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
            let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) else { return }
        let containerView = transitionContext.containerView

        if operation == .push {
            // do your animation for push
            
            toViewController.view.frame = containerView.bounds.offsetBy(dx: 0, dy: containerView.frame.size.height)
            fromViewController.view.frame = containerView.bounds
            containerView.addSubview(toViewController.view)

            UIView.animate(withDuration: transitionDuration(using: transitionContext),
                           delay: 0,
                           options: [ UIView.AnimationOptions.curveEaseOut ],
                           animations: {
                toViewController.view.frame = containerView.bounds
                               
            },
                           completion: { (finished) in
                            transitionContext.completeTransition(true)
            })
        } else if operation == .pop {
            // do your animation for pop
            containerView.addSubview(toViewController.view)
            containerView.addSubview(fromViewController.view)//containerView 上加的view在动画结束后一段时间后被释放了
            
            fromViewController.view.frame  = containerView.bounds
//            toViewController.view.frame = containerView.bounds
            UIView.animate(withDuration: transitionDuration(using: transitionContext),
                           animations: {
              
                fromViewController.view.frame = containerView.bounds.offsetBy(dx: 0, dy: containerView.frame.size.height)
            },
                           completion: { (finished) in
                            transitionContext.completeTransition(true)
                
                
            })
        }
    }
}

UINavigationController 添加delegate


class BaseNavigationController: UINavigationController {
   
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.delegate = self
        }
}

实现delegate的协议 ,返回本文最开始定义的类的对象,这里只要返回nil 就会是默认的动画方式(所以可以按照需求切换界面过渡动画)

extension BaseNavigationController : UINavigationControllerDelegate {
    
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        return NavigationControllerAnimation(operation: operation)  
    }
    
    
}

参考:
https://stackoverflow.com/questions/2215672/how-to-change-the-push-and-pop-animations-in-a-navigation-based-app

你可能感兴趣的:(UI,swift,ios)