1 移动端动画简介
现在主流的移动端平台主要是iOS和Android,而在这两个平台,都有一套自己的动画api。通过使用这些api,使用者可以实现一些基础或是复杂的动画效果。
iOS的动画系统称之为Core Animation。若要实现一个简单的线性位移动画,其代码可以写成如下样子:
CGPoint pointSrc = self.button.layer.position;
CGPoint pointDes = CGPointMake(pointSrc.x, pointSrc.y + 60);
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];
anim.duration = 5;
anim.fromValue = [NSValue valueWithCGPoint:pointSrc];
anim.toValue = [NSValue valueWithCGPoint:pointDes];
[self.button.layer addAnimation:anim forKey:nil];
代码 1
Core Animation拥有以下优点:
1) 类似视图一样,可以通过CALayer创建复杂的一些动画
2) 系统支持的动画运行在独立的线程里面,并可以独立在主线程之外
3) 提供了一套较为简单的动画api接口,支持属性动画和并行动画
4) 属性动画中,提供了较为完善的动画属性设置,通过这些属性设置,使用者可以定制更为复杂的动画,如配置动画运动轨迹、运行速率、开始延迟时间等
5) 当动画配置完成并启动后,CoreAnimation会自动控制并完成相应的动画帧
6) 提供了CAEmitterLayer,很好地支持了粒子动画
7) 具有较高地应用性能,应用程序只有在发生改变的时候才重绘。
而从使用者的另一个角度看,CoreAnimation也一些不太方便的地方:
1) 系统api并不支持全部的属性动画
除了系统支持的属性动画,其余属性的动画并不能通过现成动画类(CABasicAnimation或CAKeyframeAnimation)来实现动画,如使用者想要实现控件的宽度变化动画,此时使用者就可能就需要求助计时器,编写专门地代码,利用计时器不停地修改属性值,来达到动画效果。
2) 系统并没提供专门的api来完成串行动画
CoreAnimation提供了CAAnimationGroup,但却没提供CAAnimationSequence,由此使用者如果需要实现一个由多个属性动画串行执行的动画,就必须自己动手编写相关的逻辑,如在每个属性动画的结束的监听函数 (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag 当中启动下一个动画。
3) 动画执行的速率控制曲线并不是真正可以任意定义的
系统中提供了5种自定义的变量, 来方便使用者描述动画执行速率,见图1.
kCAMediaTimingFunctionLinear |
kCAMediaTimingFunctionEaseIn |
kCAMediaTimingFunctionEaseOut |
kCAMediaTimingFunctionEaseInEaseOut |
kCAMediaTimingFunctionDefault |
图1 系统自定义的速率控制曲线变量
除此之外,使用者可以通过定义速率控制曲线(3次bezier曲线)的中间2个控制点的坐标,来定制速率控制曲线,见代码2。使用bezier曲线会使动画过程比较光顺,然而也限制了使用者定义曲率会发生突变的曲线。
anim.timingFunction=[CAMediaTimingFunction functionWithControlPoints:0.2 :0.2 :0.8 :0.8];
代码2
Android的动画模块,支持View的补间动画、桢动画和属性动画(android3.0引入)。相比iOS的Core Animatuon,Android动画模块在以下几点更为方便:
1) 属性动画支持大部分属性
对于系统直接支持的动画属性,可通过代码3对view执行旋转动画
ObjectAnimator.ofFloat(view, "rotationX", 0.0F, 360.0F)
.setDuration(500)
.start();
代码3
对于系统不直接支持的动画属性,可通过添加AnimatorUpdateListener的监听,来修改属性值,见代码4。
ObjectAnimator anim = ObjectAnimator
.ofFloat(view, "anim", 1.0F, 0.0F)
.setDuration(500);
anim.start();
anim.addUpdateListener(new AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animation){
// here to change property values
}
});
代码4
2) 允许用户自定义动画执行的速率控制曲线
除了系统预定义的几种插值器外,如LinearInterpolator 、DecelerateInterpolator 、AccelerateInterpolator、AccelerateDecelerateInterpolator等之外,使用者可以自定义插值器,进而得到自己想要的插值器,来控制动画执行快慢。
3) 支持串行动画
AnimatorSet不仅可以实现并行动画,同时也可以实现串行动画,见代码5
AnimatorSet animSet = new AnimatorSet();
animSet.play(anim1).before(anim2);
animSet.play(anim2).with(anim3);
animSet.play(anim2).with(anim4);
animSet.play(anim5).after(amin2);
animSet.start();
代码5 动画执行顺序为anim1, (anim2, anim3, anim4同时执行), anim5
综上动画模块简介,可以看出其api对于使用者来说,还有如下几点不够友好,而ColorTouch的动画模块也就是从这几点入手,为使用者提供一套更为统一、友好、跨平台的api。
在Core Animation中,想实现width的变化动画,则需要通过其他的途径实现。在Android中,对于系统直接支持的属性动画,可用代码3实现;而对于系统不直接支持的,则必须添加监听,见代码4。
ColorTouch的动画模块为使用者提供了统一的接口,见代码6,使用者不再需要关心该动画类型是否是当前移动平台api支持的,只要该动画的属性对象是当前控件布局外观相关的一个属性。
local animObj = Button{
id = "animationObj",
left=20,top=160,
width=40,height=20,
text="I'm a Button",
}
local colorAnim = PropertyAnimation{
propertyName = "color",
duration = 5,
fromValue = {r=255,g=255,b=255,a=1},
toValue = {r=255,g=0,b=0,a=1},
target = animObj,
startOffset = 1,
}
animator:addAnimation(colorAnim)
local bgColorAnim = PropertyAnimation{
propertyName = "backgroundColor",
duration = 5,
fromValue = {r=0,g=0,b=0,a=1},
toValue = {r=0,g=255,b=0,a=1},
target = animObj,
startOffset = 1.5,
}
animator:addAnimation(bgColorAnim)
代码6
在Core Animation中,由于没有直接支持的串行动画类,由此动画的组合能力也就仅限制于构造并行动画了。而在Android当中使用AnimatorSet能将其它的Animator进行组合,进而运行出复杂的动画效果,而使用with,before,after这3个接口,个人觉得还是略繁琐。
ColorTouch动画模块中提供了ParallelAnimation和SequenceAnimation这2个类,分别用于组合并行动画和串行动画,而组合出来的动画仍然是可组合的。通过组合性,可以创造出更为复杂的动画。
local sequenceAnim1 = SequenceAnimation{
animations = {moveAnim,colorAnim,alphaAnim,},
}
local parallelAnim = ParallelAnimation{
animations = {scaleAnim,rotateAnim,},
}
local sequenceAnim2 = SequenceAnimation{
animations = {sequenceAnim1,parallelAnim,},
}
animator:addAnimation(sequenceAnim2)
代码7
sequenceAnim1定义了一个由3个属性动画组成的串行动画,parallelAnim定义了一个由2个属性动画组成的并行动画,sequenceAnim2定义了2个组合动画组成的串行动画。
Core Animation中,给动画类提供了autoReverse属性,并没有提供reverse接口来获取逆动画的实例。而在Android中,虽然对ValueAnimator、ObjectAnimator、TimeAnimator提供了reverse接口,却没有对AnimatorSet提供这个接口,即Android对基本的属性动画和组合动画是区别对待的。
ColorTouch动画模块中为属性动画、串行动画、并行动画都提供了reverse接口,由此使用者不需要关心当前动画是最简单的属性动画,还是多次组合出来后的复杂动画,通过reverse接口都能获取逆动画的实例。
local reverseAnim = complexAnim:reverse()
代码8
Core Animation中的动画缓动曲线定义仅限于3次4控制点bezier曲线,而Android中则不受这个限制。为兼容iOS和Android,ColorTouch动画模块中允许使用者自定义动画缓动曲线。当然在iOS下,使用自定义速度控制曲线的动画,则必须通过计时器完成动画。除此之外,使用者也可以使用预定义的速度控制曲线,如linearTimelineType、accelerateTimelineType、decelerateTimelineType、accelerateDecelerateTimelineType、decelerateAccelerateTimelineType,或是定义3次bezier曲线中间2个控制点的位置来确定速度控制曲线。
相关阅读:ColorTouch动画模块(下)
本文来自网易实践者社区,经作者张云龙授权发布。