上篇View Animations可以实现一些简单的动效,但并不能够完全满足开发使用,自定义程度比较低,为此我们来学习下Layer Animations.
那么Layer有哪些可以自定义动画的属性呢?
- 位置和尺寸: bounds position transform
- 边框: borderColor borderWidth cornerRadius
- 阴影: shadowOffset shadowOpacity shadowPath shadowRadius
- 内容: contents mask opacity
等等,以上仅仅只是一部分.
1.开篇
还是先从位移说起吧!还记得在上一篇View Animations中是怎么实现的吗?
现在我们可以这样做:
1 2 3 4 5 6 7 8 9 10 11 |
let flyRight = CABasicAnimation(keyPath: "position.x") // 开始时的位置 flyRight.fromValue = 80 // 结束时的位置 flyRight.toValue = 230 flyRight.duration = 0.5 // 延迟0.3执行 flyRight.beginTime = CACurrentMediaTime() + 0.3 // 添加到dogImageView上 dogImageView.layer.addAnimation(flyRight, forKey: nil) |
这边会碰到一个问题,当动画结束后dogImageView会立即返回初始的状态,那么如果要dogImageView保持在结束状态该怎样做呢?
1 2 3 4 5 6 7 8 9 10 11 12 |
let flyRight = CABasicAnimation(keyPath: "position.x") // 保证fillMode起作用 flyRight.removedOnCompletion = false // 动画结束后,layer会保持结束状态 flyRight.fillMode = kCAFillModeForwards flyRight.fromValue = 60 flyRight.toValue = 230 flyRight.duration = 0.5 // 延迟执行 flyRight.beginTime = CACurrentMediaTime() + 1 dogImageView.layer.addAnimation(flyRight, forKey: nil) |
设置fillMode的属性就行了.
fillMode的几个值的分别代表的含义:
- kCAFillModeRemoved : 默认样式 动画结束后会回到layer的开始的状态
- kCAFillModeForwards : 动画结束后,layer会保持结束状态
- kCAFillModeBackwards : layer跳到fromValue的值处,然后从fromValue到toValue播放动画,最后回到layer的开始的状态
- kCAFillModeBoth : kCAFillModeForwards和kCAFillModeBackwards的结合,即动画结束后layer保持在结束状态
fillMode = kCAFillModeBoth 演示效果:
1 2 3 4 5 6 7 8 9 10 11 |
dogImageView.layer.position.x = 80 let flyRight = CABasicAnimation(keyPath: "position.x") // 保证fillMode起作用 flyRight.removedOnCompletion = false flyRight.fillMode = kCAFillModeBoth flyRight.fromValue = 100 flyRight.toValue = 230 flyRight.duration = 0.5 flyRight.beginTime = CACurrentMediaTime() + 1 dogImageView.layer.addAnimation(flyRight, forKey: nil) |
dogImageView的初始位置为80,然后跳到100,从100开始执行动画,停在最终位置.
左面是控制台,我们给dogImageView添加了一个点击监听,发现dogImageView的位置表面上看起来是改变了,其实它还在原来的位置,也就是说layer动画并不是真实的,如果要变成真实的需要改变其position,那问题来了这个效果的使用场景是什么?
答:视图不需要交互,且动画的开始和结束需要设置特殊的值.
2.代理
如果我想在动画开始和结束的时候分别搞点事情该怎样做呢?对的,可以用代理呀!
设置下代理就能实现代理方法了.
1 2 3 4 5 6 7 8 9 10 |
flyRight.delegate = self extension ViewController { override func animationDidStart(anim: CAAnimation) { print("动画开始调用") } override func animationDidStop(anim: CAAnimation, finished flag: Bool) { print("动画结束调用") } } |
使用Layer Animations可以设置好一个Animation,然后添加到不同的view上面,但这时如果我们设置了flyRight的代理,并将flyRight添加到了很多的view上面,那该怎样才能在代理方法中区分哪个是哪个呢?
用KVC设置一个name然后在代理中做一下判断就行了.