阅读 1051

iOS自定义转场动画

     能让App高端的不仅仅是动画,但是能让App感觉高端的那绝对是动画。 公司项目是语音这块的,看了几个竞品,感觉我们的转场真是钢铁般的硬啊!大致研究了一下转场动画(Push 和 Present),运用到项目中,可以让App感觉些许高端点。

**Push转场动画:**做push转场动画的时候需要设置控制器的 navigationController设置一个代理,然后在实现如下方法:

 func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {        
    let transition = TransitionPushAniManager.init(duration: 0.5, pushType: (operation == .push) ? .push : .pop)
    return transition
 }
复制代码

TransitionPushAniManager是一个遵循了UIViewControllerAnimatedTransitioning协议的类的实例。在TransitionPushAniManager里实现协议对应的如下两个方法:

///返回动画时长 
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
     return duration
 }
  
 ///要执行的动画  
 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    if pushType == .push {
         pushAnimateTransition(using: transitionContext)
            
     } else {
         popAnimateTransition(using: transitionContext)
     }
 }
复制代码

然后在pushAnimateTransition(using: transitionContext) 和 popAnimateTransition(using: transitionContext)做动画实现!

**Model转场动画:**做模态转场动画的时候需要设置所要去的页面控制器的 transitioningDelegate设置一个代理,然后在实现如下方法:

 ///去的方法 - present
 func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
     return TransitionModalAniManager.init(duration: 0.5, modalType: .present)
 }
    
 ///回来的方法 - dismiss
 func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
     return TransitionModalAniManager.init(duration: 0.5, modalType: .dismiss)
 }
复制代码

TransitionModalAniManager是一个遵循了UIViewControllerAnimatedTransitioning协议的类的实例。在TransitionModalAniManager里实现协议和push相同的如下两个方法:

///返回动画时长 
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
     return duration
 }
  
 ///要执行的动画  
 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    if modelType == .present {
         presentAnimateTransition(using: transitionContext)
            
     } else {
         dismissAnimateTransition(using: transitionContext)
     }
 }
复制代码

然后在presentAnimateTransition(using: transitionContext)和dismissAnimateTransition(using: transitionContext)做动画!

**TabbarController的转场动画:**其实和Push、Modal相似,TabbarController的转场也是先设置UITabBarControllerDelegate代理,然后实现一个回调方法如下:

 ///UITabBarController转场
 func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
     return TransitionTabbarAniManager.init()
 }
复制代码

TransitionTabbarAniManager 是一个遵循UIViewControllerAnimatedTransitioning的类的实例,同时实现了如下方法:

 ///实现转场方法
 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
     guard let fromVc = transitionContext.viewController(forKey: .from), let fromView = fromVc.view, let toVc = transitionContext.viewController(forKey: .to), let toView = toVc.view else {
         return
     }
        
     let containerView = transitionContext.containerView
     containerView.addSubview(toView)

     let startPoint = CGPoint.init(x: 0, y: 0)
     let radius: CGFloat = 30.0
        
     //创建UIBezierPath路径 作为后面动画的起始路径
     let startPath = UIBezierPath.init(arcCenter: startPoint, radius: radius, startAngle: 0.0, endAngle: CGFloat(2 * Double.pi), clockwise: true)

     let x = startPoint.x
     let y = startPoint.y

     let radius_x = (x > containerView.frame.size.width - x) ? x : (containerView.frame.size.width - x)
     let radius_y = (y > containerView.frame.size.height - y) ? y : (containerView.frame.size.height - y)

     let endRadius = sqrt(pow(radius_x, 2) + pow(radius_y, 2))

     let endPath = UIBezierPath.init(arcCenter: startPoint, radius: endRadius, startAngle: 0, endAngle: CGFloat(2 * Double.pi), clockwise: true)

     let shapeLayer = CAShapeLayer.init()
     shapeLayer.path = endPath.cgPath
     toView.layer.mask = shapeLayer

     let animation = CABasicAnimation.init(keyPath: "path")
     animation.fromValue = startPath.cgPath
     animation.duration = duration
     shapeLayer.add(animation, forKey: nil)

     DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
         shapeLayer.removeAllAnimations()
         fromView.removeFromSuperview()
         transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
     }
 }
复制代码

大致的代码可以扫一下:转场动画

文章分类
iOS
文章标签