如果移动端访问不佳,可以访问我的个人博客

偶然间在网页上看到一个过山车动画觉得很炫,就想用swift纯代码实现了一个类似的效果,因为没有设计天赋,所以就完全高仿的人家的效果-.-下面上效果图:

仿ios过渡动画模块 仿ios全局过渡动画软件_ios

给大家介绍一下项目中主要会用到的类:

  • CAShapeLayer
  • CAGradientLayer
  • CAKeyframeAnimation

实现的主要思路

渐变的背景用CAGradientLayer实现,其他例如山峰,草坪和轨道可以用CAShapeLayer配合UIBezierPath实现,然后云朵,树木和大地直接用CALayer通过设置contents实现,然后云朵和过山车的动画实现用CAKeyframeAnimation,这样分析其实做一个这样的动态效果并不是很难,下面就是实现过程和简单的代码示例。下载demo有完整代码

CAGradientLayer

CAGradientLayer是用来生成两种或更多颜色平滑渐变的。相比于Core Graphics来说CAGradientLayer的真正好处在于绘制使用了硬件加速。这说明通过CAGradientLayer来绘制渐变的效果比用Core Graphics的效率更高。我们通过CAGradientLayer来实现这个项目中的背景下载demo有完整代码:

//初始化背景
    func initGradientLayer(size:CGSize) -> CAGradientLayer {
        let layer:CAGradientLayer = CAGradientLayer()
        layer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height - 20)
        //设置渐变的颜色
        layer.colors = [UIColor.init(colorLiteralRed: 178.0/255.0, green: 226.0/255.0, blue: 248.0/255.0, alpha: 1.0).CGColor, UIColor.init(colorLiteralRed: 232.0/255.0, green: 244.0/255.0, blue: 193.0/255.0, alpha: 1.0).CGColor]
        //设置渐变的方向为从左上到右下
        layer.startPoint = CGPoint(x: 0, y: 0)
        layer.endPoint = CGPoint(x: 1, y: 1)
        view.layer.addSublayer(layer)
        return layer
    }

仿ios过渡动画模块 仿ios全局过渡动画软件_仿ios过渡动画模块_02

CAShapeLayer

CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类。你指定诸如颜色和线宽等属性,用CGPath来定义想要绘制的图形,最后CAShapeLayer就自动渲染出来了。当然,你也可以用Core Graphics直接向原始的CALyer的内容中绘制一个路径,相比直下,使用CAShapeLayer有以下一些优点:

  • 渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
  • 高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
  • 不会被图层边界剪裁掉。一个CAShapeLayer可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉(如我们在第二章所见)。
  • 不会出现像素化。当你给CAShapeLayer做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。

我们用CAShapeLayer来绘制草地,山坡和过山车的轨道,下面给大家通过绘制草坪的代码简单介绍一下用法下载demo有完整代码:

//初始化草坪
    func initGrasslandlayer(size:CGSize) -> CAShapeLayer {
        let grasslandOne = CAShapeLayer()
        //通过UIBezierPath来绘制路径
        let pathOne:UIBezierPath = UIBezierPath()
        pathOne.moveToPoint(CGPoint(x: 0, y: size.height - 20))
        pathOne.addLineToPoint(CGPoint(x: 0, y: size.height - 100))
        pathOne.addQuadCurveToPoint(CGPoint(x: size.width/3.0, y: size.height - 20), controlPoint: CGPoint(x: size.width/6.0, y: size.height - 100))
        grasslandOne.path = pathOne.CGPath
        //设置草坪的颜色
        grasslandOne.fillColor = UIColor.init(colorLiteralRed: 82.0/255.0, green: 177.0/255.0, blue: 44.0/255.0, alpha: 1.0).CGColor
        view.layer.addSublayer(grasslandOne)
    }

仿ios过渡动画模块 仿ios全局过渡动画软件_动画_03

CAKeyframeAnimation

CAKeyframeAnimation类为对象提供了关键帧动画的功能。你创建一个CAKeyframeAnimation对象使用animationWithKeyPath:指定属性的关键路径,你可以指定要使用关键帧的值来控制时间和动画的行为。我们可以通过CAKeyframeAnimation来实现过山车在轨道上的的动画和云朵的动画,下面是一小段示例代码下载demo有完整代码:

//添加绿色轨道的动画
    func addGreenCarPathAnimation(size:CGSize) {
        let carLayer:CALayer = CALayer()
        carLayer.frame = CGRect(x: 0, y: 0, width: 17, height: 11)
        carLayer.contents = UIImage.init(named: "otherCar")!.CGImage

        //绘制路径
        let path:UIBezierPath = UIBezierPath()
        path.lineCapStyle = .Round
        path.lineJoinStyle = .Round
        path.moveToPoint(CGPoint(x: size.width + 10, y: size.height - 7))
        path.addLineToPoint(CGPoint(x: size.width + 10, y: size.height - 77))
        path.addQuadCurveToPoint(CGPoint(x: size.width/1.8, y: size.height - 77), controlPoint: CGPoint(x: size.width - 120, y: 193))
        path.addArcWithCenter(CGPoint(x: size.width/1.9, y: size.height - 140), radius: 63, startAngle: CGFloat(0.5*M_PI), endAngle: CGFloat(2.5*M_PI), clockwise: true)
        path.addCurveToPoint(CGPoint(x: 0, y: size.height - 107), controlPoint1: CGPoint(x: size.width/1.8 - 60, y: size.height - 67), controlPoint2: CGPoint(x: 150, y: size.height/2.3-7))
        path.addLineToPoint(CGPoint(x: -100, y: size.height + 7))

        //关键帧动画作用于position
        let animation:CAKeyframeAnimation = CAKeyframeAnimation.init(keyPath: "position")
        animation.path = path.CGPath
        //动画节奏为线性动画
        animation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear)
        //动画时间
        animation.duration = 6
        //动画重复次数
        animation.repeatCount = MAXFLOAT
        //动画是否逆转
        animation.autoreverses = false
        //动画速度为匀速
        animation.calculationMode = kCAAnimationCubicPaced
        //动画角度是否调整
        animation.rotationMode = kCAAnimationRotateAuto
        view.layer.addSublayer(carLayer)
        carLayer.addAnimation(animation, forKey: "carAnimation")
    }