本文摘自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, 0, height: 0)) } // 扩大的圆形路径 var endCirclePath: UIBezierPath { return UIBezierPath(ovalInRect: CGRect(x: 2.5, y: 17.5, 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, size, height: size)) view.addSubview(animationView) } }
至此为止ViewController上就会出现一个圆形的图层,最基本的操作到此为止。
抖动动画
1、在圆形图层中添加几个属性和一个动画方法:
// 横向拉伸 var circleVerticalSquishPath: UIBezierPath { return UIBezierPath(ovalInRect: CGRect(x: 2.5, y: 20.0, 95.0, height: 90.0)) } // 纵向拉伸 var circleHorizontalSquishPath: UIBezierPath { return UIBezierPath(ovalInRect: CGRect(x: 5.0, y: 17.5, 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, 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 }) } }
到此结束。