1. 为什么动画
在移动互联网的时代,移动应用的竞争不再局限于内容与技术层面,用户体验方面在愉悦用户方面越来越重要。 良好的动画效果可以让用户得到清晰的反馈、以及在复杂场景下不易迷失等好处,可以说动画是构建良好用户体验不可缺失的一环。
iOS上的动画效果主要覆盖以下几个角度:
- 视图的移动,缩放,旋转, 褪色, 加速度(Velocity),阻力(Damp);
- 渐变, 不规则形状 + 蒙版图层;
- 粒子效果;
- 3D动画;
- 视图切换动画;
iOS平台上实现动画效果有多种技术选择,如UIKit框架内的UIView、Graphics & Animation框架内的CoreAnimation。这些丰富的图形与动画技术框架是iOS平台上实现各种动画效果的基础。 第三方也有诸如Facebook的Pop动画引擎,甚至有些应用会使用OpenGL、SpriteKit、Metal等游戏引擎来实现复杂的动画效果。
2. UIView - 动画
iOS 在UIKit - UIView里封装了一些方便开发者的动画API,功能强大。
从下面的例子可以看到通过暴露的接口可以设置哪些属性。
UIView.animate(withDuration: 0.5,
delay: 0.5,
usingSpringWithDamping: 0.4,
initialSpringVelocity: 0.4,
options: UIViewAnimationOptions.curveLinear,
animations: {
//TODO
}, completion: nil)
//Transition
UIView.transition(from: UIView,
to: UIView,
duration: TimeInterval,
options: UIViewAnimationOptions,
completion: ((Bool) -> Void)?)
//KeyFrame
UIView.animateKeyframes(withDuration: TimeInterval,
delay: TimeInterval,
options: UIViewKeyframeAnimationOptions,
animations: {
//Add frame changes
UIView.addKeyframe(withRelativeStartTime: Double,
relativeDuration: Double,
animations: {
//TODO
})
},
completion: <((Bool) -> Void)?)
3. CALayer 动画
//允许对单个layer添加多个无相互依赖的动画
let flyRight = CABasicAnimation(keyPath: "position.x")
flyRight.fromValue = -view.bounds.size.width/2
flyRight.toValue = view.bounds.size.width/2
flyRight.duration = 0.5
flyLeft.repeatCount = 4
flyLeft.autoreverses = true
flyLeft.speed = 2.0
//CABasicAnimation 是纯对象,Copy对象。
heading.layer.addAnimation(flyRight, forKey: "infoappear")
//移除 animation
info.layer.removeAnimationForKey("infoappear")
//CAAnimationGroup 可以让多个无依赖动画同步进行
//CAKeyframeAnimation 对于keyframeAnimation on UIView
let wobble = CAKeyframeAnimation(keyPath: "transform.rotation") wobble.duration = 0.25
wobble.repeatCount = 4
//注意这里的values是数组类型
wobble.values = [0.0, -M_PI_4/4, 0.0, M_PI_4/4, 0.0] wobble.keyTimes = [0.0, 0.25, 0.5, 0.75, 1.0] heading.layer.addAnimation(wobble, forKey: nil)
//CAShapeLayer + UIBezierPath
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = showView.bounds; // 与showView的frame一致
layer.strokeColor = [UIColor greenColor].CGColor; // 边缘线的颜色
layer.fillColor = [UIColor clearColor].CGColor; // 闭环填充的颜色
layer.lineCap = kCALineCapSquare; // 边缘线的类型
layer.path = path.CGPath; // 从贝塞尔曲线获取到形状
layer.lineWidth = 4.0f; // 线条宽度
layer.strokeStart = 0.0f;
layer.strokeEnd = 0.1f;
//CAGradientLayer是用来生成两种或更多颜色平滑渐变的。
需要注意的是UIKit中UIBezierPath类可以创建基于矢量的路径。此类是Core Graphics框架关于CGPathRef数据的一个封装,使用此类可以定义简单的形状,如椭圆或者矩形,或者有多个直线和曲线段组成的形状。
CADisplayLink VS NSTimer
- iOS设备的屏幕每秒会刷新60次,CADisplayLink在屏幕每次刷新时都会调用,精确度非常高,并且CADisplayLink的使用场合相对专一,适合做UI的不停重绘,比如动画的连续绘制。
- NSTimer的使用范围则相对广泛,可以做单次或者循环处理某个任务,精度相比CADisplayLink要低。
CALayer拥有presentLayer, modelLayer, 在动画运行的时候,用户看到的其实是presentLayer的变化。
Core Animation相对UIView暴露的接口拥有更多灵活度和自由,可以在动画运行时监控和随时终止。
如果遇到使用UIView或CALayer相关的接口都能实现的动画,建议使用UIView封装的API接口,因为UIView封装了CAlayer相关接口,使用和维护更简单。
4. 3D 动画
上面列举的都是2D范围内的动画,Core Animation也支持3D动画。但iOS中的3D动画本质上并不能算真正的3D, 而只是3D在二维平面上的投影。
从上面图中,动画可以修改anchorPoint, position, bounds 和 frame。
var imageTransform = CATransform3DIdentity
//在某个transform3D变换的基础上进行平移变换,t是上一个transform3D,其他参数同上
imageTransform = CATransform3DTranslate( imageTransform, 0.0, imageYOffset, 0.0)
//x,y,z分别对应x轴,y轴,z轴的缩放比例
imageTransform = CATransform3DScale( imageTransform, 0.95, 0.6, 1.0)
//x,y,z决定了旋转围绕的中轴,取值为-1——1之间,例如(1,0,0),则是绕x轴旋转(0.5,0.5,0)
imageTransform = CATransform3DRotate( imageTransform, CGFloat(M_PI_4/2), -1.0, 0.0, 0.0)
image.layer.transform = imageTransform
//CATransform3DMakeTranslation
5. 粒子动画
先来看张粒子效果图, 类似效果在游戏中经常看到。
在QuartzCore框架中,CAEmitterLayer和CAEmitterCell可以帮助开发者轻松实现粒子效果。
其中CAEmitterLayer继承自CALayer,可以将一个或多个CAEmitterCell添加到上面。
CAEmitterLayer *snowEmitter = [CAEmitterLayer layer];
//例子发射位置
snowEmitter.emitterPosition = CGPointMake(120,20);
//发射源的尺寸大小
snowEmitter.emitterSize = CGSizeMake(self.view.bounds.size.width * 20, 20);
//发射模式
snowEmitter.emitterMode = kCAEmitterLayerSurface;
//发射源的形状
snowEmitter.emitterShape = kCAEmitterLayerLine;
//创建雪花类型的粒子
CAEmitterCell *snowflake = [CAEmitterCell emitterCell];
//粒子的名字
snowflake.name = @"snow";
//粒子参数的速度乘数因子
snowflake.birthRate = 1.0;
snowflake.lifetime = 120.0;
//粒子速度
snowflake.velocity =10.0;
//粒子的速度范围
snowflake.velocityRange = 10;
//粒子y方向的加速度分量
snowflake.yAcceleration = 2;
//周围发射角度
snowflake.emissionRange = 0.5 * M_PI;
//子旋转角度范围
snowflake.spinRange = 0.25 * M_PI;
snowflake.contents = (id)[[UIImage imageNamed:@"snow"] CGImage];
//设置雪花形状的粒子的颜色
snowflake.color = [[UIColor colorWithRed:0.200 green:0.258 blue:0.543 alpha:1.000] CGColor];
snowEmitter.shadowOpacity = 1.0;
snowEmitter.shadowRadius = 0.0;
snowEmitter.shadowOffset = CGSizeMake(0.0, 1.0);
//粒子边缘的颜色
snowEmitter.shadowColor = [[UIColor redColor] CGColor];
snowEmitter.emitterCells = [NSArray arrayWithObjects:snowflake,,nil];
6. View Controller转场动画
iOS中除了常见的View Controller转场动画push/present外,iOS还支持开发者定制自有的转场动画效果。
这时需要实现协议UIViewControllerAnimatedTransitioning,该协议内要实现两个方法:
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!
let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
///要点在这里
}
而对应的ViewController要实现UIViewControllerTransitioningDelegate协议。
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
///返回转场动画
}
...
更多阅读
iOS Animations by Tutorials
请关注豆志昂扬微信公众号获取更多内容:
- 直接添加公众号豆志昂扬;
- 微信扫描下图二维码;