偶然间在网页上看到一个过山车动画觉得很炫,就想用
swift
纯代码实现了一个类似的效果,因为没有设计天赋,所以就完全高仿的人家的效果-.-下面上效果图:
给大家介绍一下项目中主要会用到的类:
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
}
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)
}
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")
}
上面的代码只是简单的示例,完整代码得去我的github上去下载,到这里也就基本上完成了,大家有什么疑问可以留言评论,谢谢大家的观看