分析一个炫酷动画
本文摘自http://www.cocoachina.com/ios/20160620/16763.html,本人只是跟敲一遍然后做笔记备忘。
展示圆形图层
1、动画的最开始是一个圆形图层,首先创建一个圆形视图,继承自CAShapeLayer:
class CircleLayer: CAShapeLayer {
// MARK: 属性
let animationDuration: CFTimeInterval = 0.3
// 开始圆形路径
var beginCirclePath: UIBezierPath {
return UIBezierPath(ovalInRect: CGRect(x: 50.0, y: 50.0, width: 0, height: 0))
}
// 扩大的圆形路径
var endCirclePath: UIBezierPath {
return UIBezierPath(ovalInRect: CGRect(x: 2.5, y: 17.5, width: 95.0, height: 95.0))
}
override init() {
super.init()
// 设置自身的填充颜色。
self.fillColor = UIColor(red: 221.0 / 255.0, green: 108.0 / 255.0, blue: 217.0 / 255.0, alpha: 1.0).CGColor
self.path = beginCirclePath.CGPath
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/**
扩大动画
*/
func expand() {
let animation = CABasicAnimation(keyPath: "path")
animation.fromValue = beginCirclePath.CGPath
animation.toValue = endCirclePath.CGPath
animation.fillMode = kCAFillModeForwards
animation.removedOnCompletion = false
animation.duration = animationDuration
self.addAnimation(animation, forKey: nil)
}
}
2、创建一个Animation视图:
class AnimationView: UIView {
// MARK: 属性
let circle = CircleLayer()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.clearColor()
// 添加圆形图层
addCircleLayer()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: 添加图形
func addCircleLayer() {
self.layer.addSublayer(circle)
// 执行扩张动画
circle.expand()
}
}
3、在ViewController中添加AnimationView:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
addAnimationView()
}
func addAnimationView() {
let size: CGFloat = 100.0
let screenSize = UIScreen.mainScreen().bounds.size
let animationView = AnimationView(frame: CGRect(x: screenSize.width / 2 - size / 2, y: screenSize.height / 2 - size / 2, width: size, height: size))
view.addSubview(animationView)
}
}
至此为止ViewController上就会出现一个圆形的图层,最基本的操作到此为止。
抖动动画
1、在圆形图层中添加几个属性和一个动画方法:
// 横向拉伸
var circleVerticalSquishPath: UIBezierPath {
return UIBezierPath(ovalInRect: CGRect(x: 2.5, y: 20.0, width: 95.0, height: 90.0))
}
// 纵向拉伸
var circleHorizontalSquishPath: UIBezierPath {
return UIBezierPath(ovalInRect: CGRect(x: 5.0, y: 17.5, width: 90.0, height: 90.0))
}
/**
抖动动画
*/
func wobbleAnimate() {
let animation1 = CABasicAnimation(keyPath: "path")
animation1.fromValue = endCirclePath.CGPath
animation1.toValue = circleVerticalSquishPath.CGPath
animation1.beginTime = 0.0
animation1.duration = animationDuration
let animation2 = CABasicAnimation(keyPath: "path")
animation2.fromValue = circleVerticalSquishPath.CGPath
animation2.toValue = circleHorizontalSquishPath.CGPath
animation2.beginTime = animation1.beginTime + animation1.duration
animation2.duration = animationDuration
let animation3 = CABasicAnimation(keyPath: "path")
animation3.fromValue = circleHorizontalSquishPath.CGPath
animation3.toValue = circleVerticalSquishPath.CGPath
animation3.beginTime = animation2.beginTime + animation2.duration
animation3.duration = animationDuration
let animation4 = CABasicAnimation(keyPath: "path")
animation4.fromValue = circleVerticalSquishPath.CGPath
animation4.toValue = endCirclePath.CGPath
animation4.beginTime = animation3.beginTime + animation3.duration
animation4.duration = animationDuration
let animationGroup = CAAnimationGroup()
animationGroup.animations = [animation1, animation2, animation3, animation4]
animationGroup.duration = 4 * animationDuration
animationGroup.repeatCount = 2
addAnimation(animationGroup, forKey: nil)
}
2、在AnimationView中调用上面新添加的动画方法,但是要注意需要等放大动画执行完毕后。修改addCircleLayer方法:
// MARK: 添加图形
func addCircleLayer() {
self.layer.addSublayer(circle)
// 执行扩张动画
circle.expand()
// 这里需要用到计时器,以防两个动画一起执行
NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: #selector(AnimationView.wobbleCircleLayer), userInfo: nil, repeats: false)
}
func wobbleCircleLayer() {
circle.wobbleAnimate()
}
圆形边缘突出动画
分析:其实是一个三角形的三个角逐个拉伸产生的效果
1、先创建一个三角形图层:
class TriangleLayer: CAShapeLayer {
// 距离大三角形的距离
let paddingSpace: CGFloat = 30.0
// 小三角形路径
var smallTrianglePath: UIBezierPath {
let smallPath = UIBezierPath()
smallPath.moveToPoint(CGPoint(x: 5.0 + paddingSpace, y: 95.0))
smallPath.addLineToPoint(CGPoint(x: 50.0, y: 12.5 + paddingSpace))
smallPath.addLineToPoint(CGPoint(x: 95.0 - paddingSpace, y: 95.0))
smallPath.closePath()
return smallPath
}
override init() {
super.init()
let color = UIColor(red: 221.0 / 255.0, green: 108.0 / 255.0, blue: 217.0 / 255.0, alpha: 1.0).CGColor
// 设置填充色
fillColor = color
// 设置线条颜色
strokeColor = color
// 设置线条粗细
lineWidth = 7.0
// 设置圆角
lineCap = kCALineCapRound
lineJoin = kCALineJoinRound
// 首先设置path是小三角形
path = smallTrianglePath.CGPath
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
2、三角形图层实在执行到抖动动画时添加上去的:
// 新属性
let triangle = TriangleLayer()
// 修改wobbleCircleLayer()方法
func wobbleCircleLayer() {
circle.wobbleAnimate()
layer.addSublayer(triangle)
}
3、在TriangleLayer新设置左边突出路径、右边突出路径、和顶部突出路径,三角形突出动画:
// 左边突出
var leftTrianglePath: UIBezierPath {
let leftPath = UIBezierPath()
leftPath.moveToPoint(CGPoint(x: 5.0, y: 95.0))
leftPath.addLineToPoint(CGPoint(x: 50.0, y: 12.5 + paddingSpace))
leftPath.addLineToPoint(CGPoint(x: 95.0 - paddingSpace, y: 95.0))
leftPath.closePath()
return leftPath
}
// 右边突出
var rightTrianglePath: UIBezierPath {
let rightPath = UIBezierPath()
rightPath.moveToPoint(CGPoint(x: 5.0, y: 95.0))
rightPath.addLineToPoint(CGPoint(x: 50.0, y: 12.5 + paddingSpace))
rightPath.addLineToPoint(CGPoint(x: 95.0, y: 95.0))
rightPath.closePath()
return rightPath
}
// 顶部突出
var topTrianglePath: UIBezierPath {
let topPath = UIBezierPath()
topPath.moveToPoint(CGPoint(x: 5.0, y: 95.0))
topPath.addLineToPoint(CGPoint(x: 50.0, y: 12.5))
topPath.addLineToPoint(CGPoint(x: 95.0, y: 95.0))
topPath.closePath()
return topPath
}
// 突出动画
func triangleAnimation() {
// left
let triangleAnimationLeft: CABasicAnimation = CABasicAnimation(keyPath: "path")
triangleAnimationLeft.fromValue = smallTrianglePath.CGPath
triangleAnimationLeft.toValue = leftTrianglePath.CGPath
triangleAnimationLeft.beginTime = 0.0
triangleAnimationLeft.duration = 0.3
// right
let triangleAnimationRight: CABasicAnimation = CABasicAnimation(keyPath: "path")
triangleAnimationRight.fromValue = leftTrianglePath.CGPath
triangleAnimationRight.toValue = rightTrianglePath.CGPath
triangleAnimationRight.beginTime = triangleAnimationLeft.beginTime + triangleAnimationLeft.duration
triangleAnimationRight.duration = 0.25
// top
let triangleAnimationTop: CABasicAnimation = CABasicAnimation(keyPath: "path")
triangleAnimationTop.fromValue = rightTrianglePath.CGPath
triangleAnimationTop.toValue = topTrianglePath.CGPath
triangleAnimationTop.beginTime = triangleAnimationRight.beginTime + triangleAnimationRight.duration
triangleAnimationTop.duration = 0.20
// group
let triangleAnimationGroup: CAAnimationGroup = CAAnimationGroup()
triangleAnimationGroup.animations = [triangleAnimationLeft, triangleAnimationRight, triangleAnimationTop]
triangleAnimationGroup.duration = triangleAnimationTop.beginTime + triangleAnimationTop.duration
triangleAnimationGroup.fillMode = kCAFillModeForwards
triangleAnimationGroup.removedOnCompletion = false
addAnimation(triangleAnimationGroup, forKey: nil)
}
4、在抖动动画进行到一定时间时执行三角形突出动画(在AnimationView中设置):
// 圆形抖动动画
func wobbleCircleLayer() {
circle.wobbleAnimate()
layer.addSublayer(triangle)
// 同样启用定时器,以防止动画同时产生
NSTimer.scheduledTimerWithTimeInterval(0.9, target: self, selector: #selector(AnimationView.showTriangleAnimation), userInfo: nil, repeats: false)
}
// 三角形突出动画
func showTriangleAnimation() {
triangle.triangleAnimation()
}
旋转动画
1、在旋转的同时需要把圆形视图缩小,在圆形视图类中添加缩小方法:
/**
缩小动画
*/
func contract() {
let animation = CABasicAnimation(keyPath: "path")
animation.fromValue = endCirclePath.CGPath
animation.toValue = beginCirclePath.CGPath
animation.fillMode = kCAFillModeForwards
animation.removedOnCompletion = false
animation.duration = animationDuration
self.addAnimation(animation, forKey: nil)
}
2、新添加旋转方法:
// 三角形突出动画
func showTriangleAnimation() {
triangle.triangleAnimation()
// 旋转图层
NSTimer.scheduledTimerWithTimeInterval(0.9, target: self, selector: #selector(AnimationView.transformAnimation), userInfo: nil, repeats: false)
}
func transformAnimation() {
// 按照z轴旋转
transformRotationZ()
// 把圆形图层缩小
circle.contract()
}
func transformRotationZ() {
// 设置一个合适的锚点
layer.anchorPoint = CGPointMake(0.5, 0.65)
let rotation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.toValue = CGFloat(M_PI * 2)
rotation.duration = 0.45
rotation.removedOnCompletion = true
layer.addAnimation(rotation, forKey: nil)
}
绘制矩形动画
1、创建一个矩形图层:
class RectangleLayer: CAShapeLayer {
// 矩形路径
var rectanglePath: UIBezierPath {
let rectangle = UIBezierPath()
rectangle.moveToPoint(CGPointMake(0.0, 100.0))
rectangle.addLineToPoint(CGPointMake(0.0, -lineWidth))
rectangle.addLineToPoint(CGPointMake(100.0, -lineWidth))
rectangle.addLineToPoint(CGPointMake(100.0, 100.0))
rectangle.addLineToPoint(CGPointMake(-lineWidth / 2, 100.0))
rectangle.closePath()
return rectangle
}
override init() {
super.init()
// 设置填充色为透明
fillColor = UIColor.clearColor().CGColor
lineWidth = 5.0
// 设置路径
path = rectanglePath.CGPath
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 绘制矩形
func strokeChangeWithColor(color: UIColor) {
strokeColor = color.CGColor
let strokeAnimation = CABasicAnimation(keyPath: "strokeEnd")
strokeAnimation.fromValue = 0.0
strokeAnimation.toValue = 1.0
strokeAnimation.duration = 0.4
addAnimation(strokeAnimation, forKey: nil)
}
}
2、矩形动画是在缩小圆形图层后开始执行的,修改Animation的transformAnimation()方法:
let redRectangleLayer = RectangleLayer()
let blueRectangleLayer = RectangleLayer()
func transformAnimation() {
// 按照z轴旋转
transformRotationZ()
// 把圆形图层缩小
circle.contract()
// 执行矩形动画
NSTimer.scheduledTimerWithTimeInterval(0.45, target: self, selector: #selector(AnimationView.drawRedRectangleAnimation), userInfo: nil, repeats: false)
NSTimer.scheduledTimerWithTimeInterval(0.65, target: self, selector: #selector(AnimationView.drawBlueRectangleAnimation), userInfo: nil, repeats: false)
}
func drawRedRectangleAnimation() {
layer.addSublayer(redRectangleLayer)
redRectangleLayer.strokeChangeWithColor(UIColor(red: 221.0 / 255.0, green: 108.0 / 255.0, blue: 217.0 / 255.0, alpha: 1.0))
}
func drawBlueRectangleAnimation() {
layer.addSublayer(blueRectangleLayer)
blueRectangleLayer.strokeChangeWithColor(UIColor(red: 51.0 / 255.0, green: 226.0 / 255.0, blue: 175.0 / 255.0, alpha: 1.0))
}
水波纹动画
1、首先创建水波纹视图
class WaveLayer: CAShapeLayer {
let animationDuration: CFTimeInterval = 0.18
// 最开始的状态 没有水波纹
var wavePathPre: UIBezierPath {
let arcPath = UIBezierPath()
arcPath.moveToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 99.0))
arcPath.addLineToPoint(CGPoint(x: 100.0, y: 99.0))
arcPath.addLineToPoint(CGPoint(x: 100.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.closePath()
return arcPath
}
// 水波纹到20%的程度
var wavePathStarting: UIBezierPath {
let arcPath = UIBezierPath()
arcPath.moveToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 80.0))
arcPath.addCurveToPoint(CGPoint(x: 100.0, y: 80.0), controlPoint1: CGPoint(x: 30.0, y: 70.0), controlPoint2: CGPoint(x: 40.0, y: 90.0))
arcPath.addLineToPoint(CGPoint(x: 100.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.closePath()
return arcPath
}
// 水波纹到40%的程度
var wavePathLow: UIBezierPath {
let arcPath = UIBezierPath()
arcPath.moveToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 60.0))
arcPath.addCurveToPoint(CGPoint(x: 100.0, y: 60.0), controlPoint1: CGPoint(x: 30.0, y: 65.0), controlPoint2: CGPoint(x: 40.0, y: 50.0))
arcPath.addLineToPoint(CGPoint(x: 100.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.closePath()
return arcPath
}
// 水波纹到60%的程度
var wavePathMid: UIBezierPath {
let arcPath = UIBezierPath()
arcPath.moveToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 40.0))
arcPath.addCurveToPoint(CGPoint(x: 100.0, y: 40.0), controlPoint1: CGPoint(x: 30.0, y: 30.0), controlPoint2: CGPoint(x: 40.0, y: 50.0))
arcPath.addLineToPoint(CGPoint(x: 100.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.closePath()
return arcPath
}
// 水波纹到80%的程度
var wavePathHigh: UIBezierPath {
let arcPath = UIBezierPath()
arcPath.moveToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 20.0))
arcPath.addCurveToPoint(CGPoint(x: 100.0, y: 20.0), controlPoint1: CGPoint(x: 30.0, y: 25.0), controlPoint2: CGPoint(x: 40.0, y: 10.0))
arcPath.addLineToPoint(CGPoint(x: 100.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.closePath()
return arcPath
}
// 完全填满的程度
var wavePathComplete: UIBezierPath {
let arcPath = UIBezierPath()
arcPath.moveToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: -5.0))
arcPath.addLineToPoint(CGPoint(x: 100.0, y: -5.0))
arcPath.addLineToPoint(CGPoint(x: 100.0, y: 100.0))
arcPath.addLineToPoint(CGPoint(x: 0.0, y: 100.0))
arcPath.closePath()
return arcPath
}
override init() {
super.init()
fillColor = UIColor(red: 51.0 / 255.0, green: 226.0 / 255.0, blue: 175.0 / 255.0, alpha: 1.0).CGColor
path = wavePathPre.CGPath
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 执行动画
func animate() {
let waveAnimationPre: CABasicAnimation = CABasicAnimation(keyPath: "path")
waveAnimationPre.fromValue = wavePathPre.CGPath
waveAnimationPre.toValue = wavePathStarting.CGPath
waveAnimationPre.beginTime = 0.0
waveAnimationPre.duration = animationDuration
let waveAnimationLow: CABasicAnimation = CABasicAnimation(keyPath: "path")
waveAnimationLow.fromValue = wavePathStarting.CGPath
waveAnimationLow.toValue = wavePathLow.CGPath
waveAnimationLow.beginTime = waveAnimationPre.beginTime + waveAnimationPre.duration
waveAnimationLow.duration = animationDuration
let waveAnimationMid: CABasicAnimation = CABasicAnimation(keyPath: "path")
waveAnimationMid.fromValue = wavePathLow.CGPath
waveAnimationMid.toValue = wavePathMid.CGPath
waveAnimationMid.beginTime = waveAnimationLow.beginTime + waveAnimationLow.duration
waveAnimationMid.duration = animationDuration
let waveAnimationHigh: CABasicAnimation = CABasicAnimation(keyPath: "path")
waveAnimationHigh.fromValue = wavePathMid.CGPath
waveAnimationHigh.toValue = wavePathHigh.CGPath
waveAnimationHigh.beginTime = waveAnimationMid.beginTime + waveAnimationMid.duration
waveAnimationHigh.duration = animationDuration
let waveAnimationComplete: CABasicAnimation = CABasicAnimation(keyPath: "path")
waveAnimationComplete.fromValue = wavePathHigh.CGPath
waveAnimationComplete.toValue = wavePathComplete.CGPath
waveAnimationComplete.beginTime = waveAnimationHigh.beginTime + waveAnimationHigh.duration
waveAnimationComplete.duration = animationDuration
/// 动画组
let arcAnimationGroup: CAAnimationGroup = CAAnimationGroup()
arcAnimationGroup.animations = [waveAnimationPre, waveAnimationLow, waveAnimationMid, waveAnimationHigh, waveAnimationComplete]
arcAnimationGroup.duration = waveAnimationComplete.beginTime + waveAnimationComplete.duration
arcAnimationGroup.fillMode = kCAFillModeForwards
arcAnimationGroup.removedOnCompletion = false
addAnimation(arcAnimationGroup, forKey: nil)
}
}
2、水波纹动画是在矩形动画完成后:
func drawBlueRectangleAnimation() {
layer.addSublayer(blueRectangleLayer)
blueRectangleLayer.strokeChangeWithColor(UIColor(red: 51.0 / 255.0, green: 226.0 / 255.0, blue: 175.0 / 255.0, alpha: 1.0))
NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(AnimationView.drawWaveAnimation), userInfo: nil, repeats: false)
}
func drawWaveAnimation() {
layer.addSublayer(waveLayer)
waveLayer.animate()
}
放大动画并显示welcome
1、首先在AnimationView中新添加一些属性和一个协议:
@objc protocol AnimationViewDelegate: class {
optional func completeAnimation()
}
class AnimationView: UIView {
// 以下是新添加的属性和方法
// 放大的frame,由外界设置
var parentFrame = CGRectZero
// 设置一个代理
var delegate: AnimationViewDelegate?
func drawWaveAnimation() {
layer.addSublayer(waveLayer)
waveLayer.animate()
NSTimer.scheduledTimerWithTimeInterval(0.9, target: self, selector: #selector(AnimationView.expandView), userInfo: nil, repeats: false)
}
func expandView() {
backgroundColor = UIColor(red: 51.0 / 255.0, green: 226.0 / 255.0, blue: 175.0 / 255.0, alpha: 1.0)
// 清空所有sublayer
layer.sublayers = nil
frame = CGRectMake(frame.origin.x - blueRectangleLayer.lineWidth,
frame.origin.y - blueRectangleLayer.lineWidth,
frame.size.width + blueRectangleLayer.lineWidth * 2,
frame.size.height + blueRectangleLayer.lineWidth * 2)
// 执行动画
UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveEaseInOut, animations: {
self.frame = self.parentFrame
}) { (finished) in
self.delegate?.completeAnimation()
}
}
}
2、在ViewController中修改以下代码:
class ViewController: UIViewController, AnimationViewDelegate {
weak var animationView: AnimationView?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
addAnimationView()
}
func addAnimationView() {
let size: CGFloat = 100.0
let screenSize = UIScreen.mainScreen().bounds.size
let animationView = AnimationView(frame: CGRect(x: screenSize.width / 2 - size / 2, y: screenSize.height / 2 - size / 2, width: size, height: size))
animationView.parentFrame = view.frame
animationView.delegate = self
view.addSubview(animationView)
self.animationView = animationView
}
// MARK: AnimationView的代理方法
func completeAnimation() {
// 1
animationView!.removeFromSuperview()
view.backgroundColor = UIColor(red: 51.0 / 255.0, green: 226.0 / 255.0, blue: 175.0 / 255.0, alpha: 1.0)
// 2
let label: UILabel = UILabel(frame: view.frame)
label.textColor = UIColor.whiteColor()
label.font = UIFont(name: "HelveticaNeue-Thin", size: 50.0)
label.textAlignment = NSTextAlignment.Center
label.text = "Welcome"
label.transform = CGAffineTransformScale(label.transform, 0.25, 0.25)
view.addSubview(label)
// 3
UIView.animateWithDuration(0.4, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.1, options: UIViewAnimationOptions.CurveEaseInOut,animations: ({
label.transform = CGAffineTransformScale(label.transform, 4.0, 4.0)
}), completion: { finished in
})
}
}
到此结束。

浙公网安备 33010602011771号