美文网首页
Swift转场动画

Swift转场动画

作者: 一把好刀 | 来源:发表于2019-04-30 17:31 被阅读0次

    源码Github地址

    • 系统模态跳转
    // 
    open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil)
    
    // 动画风格
    public enum UIModalTransitionStyle : Int {
    
        // 默认,从底部划入
        case coverVertical
        // 切换正反面效果
        case flipHorizontal
        // 渐变效果
        case crossDissolve
        @available(iOS 3.2, *)
        // 翻页效果
        case partialCurl
    }
    
    • 模态跳转退回上一层控制器
     open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)
    
    • push动画转场,支持右滑返回,当前控制器不是navigationController的子控制器时无效
    open func pushViewController(_ viewController: UIViewController, animated: Bool)
    
    • push动画转场退回上一层控制器
    open func popViewController(animated: Bool) -> UIViewController?
    
    • push动画转场退回根控制器
     open func popToRootViewController(animated: Bool) -> [UIViewController]? 
    
    • push动画转场退回指定控制器
    open func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? 
    


    以上转场动画为系统提供,可以满足我们大部分使用场景,但是有时候我们可能会遇到特殊的需求,需要我们自定义转场动画

    /// 创建一个动画管理类,这个类可以作为所有自定义转场动画的基类
    class ZQBaseAninatedTranistion: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning {
        /**动画时长*/
        var animateDuration:TimeInterval = 0.5
        /**判断是否已经弹出*/
        var isPopup:Bool = false
        /**交互状态*/
        var isInteraction:Bool = false
        /**转场上下文*/
        var context:UIViewControllerContextTransitioning?
        /**视图*/
        var containerView:UIView?
        /**当前view*/
        var fromView:UIView?
        /**目标view*/
        var toView:UIView?
        /**当前控制器*/
        var fromViewController:UIViewController?
        /**目标控制器*/
        var toViewController:UIViewController?
        
        /// 设置动画时长
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            context = transitionContext
            return animateDuration
        }
        
        /// 执行动画过程
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            context = transitionContext
            //容器
            containerView = transitionContext.containerView
            //目标控制器
            fromViewController = transitionContext.viewController(forKey: .from)
            toViewController = transitionContext.viewController(forKey: .to)
            fromView = fromViewController?.view
            toView = toViewController?.view
            isPopup ? dismiss():present()
        }
        
        /// 弹出转场动画写在这里
        func present(){
        
        }
        
       
        /// 退回转场动画写在这里
        func dismiss(){
        }
    }
    

    实现从微信进入小程序的转场动画及右滑返回动画

    class ZQFullCoverAnimatedTranistion: ZQBaseAninatedTranistion {
        //最大偏移位置
        var maxOffset:CGFloat = 0.0
        //最右临界值
        var rightCritcal:CGFloat = 20.0
        //手势
        var leftPanGesture:UIScreenEdgePanGestureRecognizer?
        
        /// 启用边缘滑动返回
        func usingLeftSwipDismiss(view:UIView){
            //监听边缘滑动
            leftPanGesture  = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(self.onEdgeSlide))
            //左侧边缘滑动
            leftPanGesture!.edges = .left
            //添加事件
            view.addGestureRecognizer(leftPanGesture!)
        }
        
        /// 当边缘滑动
        @objc func onEdgeSlide(reco:UIScreenEdgePanGestureRecognizer){
            let point = reco.location(in: reco.view)
            //执行动画转场
            let progress = point.x / reco.view!.bounds.width
            if reco.state == .began {
                //变更状态
                isInteraction = true
                //当开始,复位
                maxOffset = 0.0
                //---------这行很关键-----------
                fromViewController?.dismiss(animated: true, completion: nil)
            } else if reco.state == .changed {
                maxOffset = max(point.x, maxOffset)
                update(progress)
            } else {
                //当结束后
                if point.x >= maxOffset && point.x > rightCritcal {
                    //完成退出
                    finish()
                }else {
                    //取消后恢复
                    cancel()
                }
                //变更状态
                isInteraction = false
            }
        }
        
        /// 弹出动画,你可以在这这个方法里面实现你想要的任意动画
        override func present(){
            //目标视图
            let toFrame = context!.finalFrame(for: toViewController!)
            //添加视图
            containerView!.addSubview(toView!)
            let rect = containerView!.bounds
            //设置动画
            toView!.frame = CGRect(x: 0, y: rect.height * 2, width: rect.width, height: rect.height)
            UIView.animate(withDuration: animateDuration, animations: { [weak self] in
                self!.toView!.frame.origin.y = 0
                self!.fromView!.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
            }) {[weak self] (r) in
                if self!.context!.transitionWasCancelled {
                    //操作失败了
                    self!.context!.completeTransition(false)
                    //移除视图
                    self!.toView?.removeFromSuperview()
                }else{
                    self!.isPopup = true
                    self!.toView?.frame = toFrame
                    self!.context!.completeTransition(true)
                }
            }
        }
        
        /// 弹回动画,你可以在这这个方法里面实现你想要的任意动画
        override func dismiss(){
            //添加toView到底部一层
            containerView!.addSubview(toView!)
            containerView!.sendSubviewToBack(toView!)
            //添加视图
            let rect = containerView!.bounds
            //设置动画
            UIView.animate(withDuration: animateDuration, animations: { [weak self] in
                self!.fromView?.frame.origin.y = rect.height * 2
                self!.toView?.transform = .identity
            }) { [weak self] (r) in
                //取消
                if self!.context!.transitionWasCancelled {
                    //操作失败
                    self!.context?.completeTransition(false)
                    self!.toView?.removeFromSuperview()
                }else{
                    self!.isPopup = false
                    //将原始视图移除
                    self!.fromView?.removeFromSuperview()
                    //通知系统是否被取消,用于记录动画是否完成
                    self!.context!.completeTransition(true)
                    //移除手势
                    if self!.leftPanGesture != nil && self!.fromView != nil{
                        self!.fromView?.removeGestureRecognizer(self!.leftPanGesture!)
                    }
                }
            }
        }
    }
    

    调用

    class ViewController: UIViewController {
        // 动画
        let tranistionHandler = ZQFullCoverAnimatedTranistion()
        override func viewDidLoad() {
            super.viewDidLoad()
    
        }
    
        
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            let vc = ZQFullCoverToViewController()
            /// 设置动画代理
            vc.transitioningDelegate = self
            // 开启右滑返回
            tranistionHandler.usingLeftSwipDismiss(view: vc.view)
            present(vc, animated: true, completion: nil)
        }
    }
    
    extension ViewController:UIViewControllerTransitioningDelegate{
        
        /// 弹出
        ///
        /// - Parameters:
        ///   - presented: 目标
        ///   - presenting: 当前
        ///   - source: 资源
        /// - Returns: 自定义的动画
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return tranistionHandler
        }
        
        /// 收起
        ///
        /// - Parameter dismissed: 目标
        /// - Returns: 自定义的动画
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return tranistionHandler
        }
        
        /// 响应手势操作
        ///
        /// - Parameter animator: tranistionHandler
        /// - Returns: 自定义的动画
        func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
            //避免手势与显示调用冲突,导致无法dismiss
            if !tranistionHandler.isInteraction {
                return nil
            }
            return tranistionHandler
        }
    }
    

    源码Github地址

    如果有帮到您,请点个喜欢

    相关文章

      网友评论

          本文标题:Swift转场动画

          本文链接:https://www.haomeiwen.com/subject/bdnvnqtx.html