在iOS 开发中,要做一个动画效果,我们会用到**CAKeyframeAnimation**。
这个库提供了一些对frame 动画的控制。 与在CAKeyframeAnimation 的概念是一样, 你只需要提供keyframe 的信息, 程序会自动完成keyframe之间的”图画”。
例: 如果想对一个图形做一个弹出的动画, 用CAKeyframeAnimation可以写成
CAKeyframeAnimation *boundsOvershootAnimation = [CAKeyframeAnimation animationWithKeyPath:@"bounds.size"];
CGSize startingSize = CGSizeZero;
CGSize targetSize = CGSizeMake(100,100);
CGSize overshootSize = CGSizeMake(120,120);
CGSize undershootSize = CGSizeMake(80,80);
NSArray *boundsValues = [NSArray arrayWithObjects:[NSValue valueWithCGSize:startingSize],
[NSValue valueWithCGSize:targetSize],
[NSValue valueWithCGSize:overshootSize],
[NSValue valueWithCGSize:undershootSize],
[NSValue valueWithCGSize:targetSize], nil];
[boundsOvershootAnimation setValues:boundsValues];
NSArray *times = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:0.5f],
[NSNumber numberWithFloat:0.8f],
[NSNumber numberWithFloat:0.9f],
[NSNumber numberWithFloat:1.0f], nil];
[boundsOvershootAnimation setKeyTimes:times];
boundsOvershootAnimation.duration = 1.0;
这个弹出的动画包含了5个keyframe, 目的是令弹出带点跳动的感觉。 [boundsOvershootAnimation setValues:boundsValues] 这一行代码就设定了这动画的keyframe。 另一个重要的元素就是时间, CAKeyframeAnimation 提供了keyframe 时间的控制, 如果不设定便会以直线性发展。 而这动画会以先慢後快的形式出现, 为什麽呢? 请看[boundsOvershootAnimation setKeyTimes:times] 这一段。 动画长一秒, 由0-0.5秒会进行 startingSize 到 targetSize 的动画, 0.5-0.8秒会进行 targetSize 到 overshootSize 的动画。 如此类推就会做出先慢後快的效果。
例2,一个透明淡出的动画
CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
opacityAnimation.fromValue = [NSNumber numberWithFloat:1.0f];
opacityAnimation.toValue = [NSNumber numberWithFloat:0.0f];
opacityAnimation.timingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
// EaseIn curve
//opacityAnimation.timingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
// EaseOut curve
//opacityAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:1.0 :0.0 :1.0 :0.1];
// Bezier curve
opacityAnimation.timingFunction 是用来控制动画线性发展。 其中[CAMediaTimingFunction functionWithControlPoints:1.0 :0.0 :1.0 :0.1] 是一个贝塞尔曲线的控制方法。 这也可以令动画做到先慢後快或先快後慢的结果。
例3,皮球跳动的效果
EasingFunction easingFn = [Easing getBounce];
CAKeyframeAnimation *transAnimi = [CAKeyframeAnimation animationWithKeyPath:@"position.x" easeFunction:easingFn.easeOut fromValue:0.0 toValue:200];
transAnimi.duration = 3.0;
[Easing getBounce] 是Tween动画库内跳动效果的公式。 [CAKeyframeAnimation animationWithKeyPath:@”position.x” easeFunction:easingFn.easeOut fromValue:0.0 toValue:200]是CAKeyframeAnimation的扩展。 回传的是一般CAKeyframeAnimation, 可以直接用在UIView 物件上。
一,速度控制函数(CAMediaTimingFunction)
1》.kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉
2》.kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开
3》.kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地
4》.kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。
CAAnimation在分类中定义了代理方法
@interfaceNSObject (CAAnimationDelegate)
-(void)animationDidStart:(CAAnimation )anim;
-(void)animationDidStop:(CAAnimation )anim finished:(BOOL)flag;
@end
pragmamark 暂停CALayer的动画
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layerconvertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed=0.0; // 让CALayer的时间停止走动
layer.timeOffset=pausedTime; // 让CALayer的时间停留在pausedTime这个时刻
}
pragmamark 恢复CALayer的动画
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime =layer.timeOffset;
layer.speed=1.0; // 让CALayer的时间继续行走
layer.timeOffset=0.0; // 取消上次记录的停留时刻
layer.beginTime=0.0; // 取消上次设置的时间
//计算暂停的时间(这里用CACurrentMediaTime()-pausedTime也是一样的)
CFTimeInterval timeSincePause = [layerconvertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
//设置相对于父坐标系的开始时间(往后退timeSincePause)
layer.beginTime = timeSincePause;
}
二,Tween动画库是可以再扩展。参考下列直线性的公式, t是当前时间值, b是属性开始值, c是属性变化差, d是总时间值, 回传的是t时间的属性值。大家可以自由改变去创建一个新的公式。
+(EasingFunction)getLinear{
EasingFunction ease;
ease.easeIn = ^double(double t, double b, double c, double d) {
return c*t/d + b;
};
ease.easeOut = ^double(double t, double b, double c, double d) {
return c*t/d + b;
};
ease.easeInOut = ^double(double t, double b, double c, double d) {
return c*t/d + b;
};
return ease;
}