核心动画

来源:互联网 发布:云涯seo 编辑:程序博客网 时间:2024/05/09 12:30

CAAnimation— CoreAnimation

核心动画主要是为了给用户最大的动画体验而开放出来的api,更加灵活,同时也意味着更加复杂。

创建动画:打开CAAnimation.h 可以很清楚的看到animation的定义.
CAAnimation作为一个父类,主要负责定义属性,方法。
其子类CABasicAnimationCAKeyframeAnimationCASpringAnimation 才是我们经常使用的类。

举个简单的例子来说明常用的字段的意思:

CABasicAnimation *animation = \
[CABasicAnimation animationWithKeyPath:@"position.x"];
animation.fromValue = @(100);
animation.toValue = @(200);
animation.duration = 3.0;
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.delegate = self;
animation.autoreverses = YES;
[self.animationView.layer addAnimation:animation forKey:@"anitio”];

这段代码实现的效果是,self.animationView的中心点在X轴方向在3.0秒内从100到200做了一段位移。

一段段代码解释:

CABasicAnimation *animation = \
[CABasicAnimation animationWithKeyPath:(nullable NSString *)];

keyPathNSString字符串。是你动画的依据,比如你要移动位置,那么keyPath就是@“position”,并且keyPath支持属性.运算:例如想做一个绕X轴旋转动画,keyPath就是@“transform.rotaion.x”
keyPath必须是可靠的,不是随便写的,那么这些值从哪儿来呢,首先layer里面的所有属性都是可以的,position就是layer的属性,position.x也可以的。为什么keyPath不能随便写,因为其对应的值是有效的,随便写因为查不到对应的方法,是没有任何动画效果的。

fromValuetoValue 是两个对应的值,看字面的意思就可以理解,从fromValuetoValue进行线性改变,这个值作用在keyPath上面。需要注意的是 fromValuetoValue都是对象,所以填充值需要注意类型。桥接或者转为NSValue.

duration是动画的持续时间,单位是秒。

removedOnComplete设置动画结束后是否结束。YES表示动画结束后移除动画效果,NO表示不移除。但是当设置NO的时候发现这个时候动画还是会有个闪动,回归原位置,那是因为动画虽然没有移除,但是动画效果不作用于属性值的修改,例如上面例子中self.animationView这个时候的center(100,150),动画效果是X从100-200进行动画,在动画结束后,X还在100的位置,而不是200。这个也是核心动画和[UIView animation]的区别,UIView动画是属性值的直接修改。

fillMode 是当removeOnCompleteNO的时候,layer对于最终动画的位置,
有四个值:kCAFillModeForwardskCAFillModeBackwardskCAFillModeBothkCAFillModeRemoved
效果backwardsremoved是一致的,表现出来的都是原始状态,至于其他区别我不知道。。
forwards效果是最终效果是和动画最终效果一致。

delegate是代理,只有两个代理方法
- (void)animationDidStart:(CAAnimation *)anim;//动画开始前
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;//动画结束
在这两个代理写一些处理方法。

autoreverses是设置动画是否返回原始效果,如设置YES,在X 从100-200动画完成之后,又会200-100的动画,如果在做摄像头扫描效果用这个参数就很省力了。

然后给layer加上animation GPU就会根据设置的参数,进行着动画。
这儿的[self.animationView.layer addAnimation:animation forKey:@"anitio”]; key是给动画的key值,可以为空,但是如果想在代理里面区分出来是哪一个animation,这儿的key就必须有,且唯一。判断方式为:

 #pragma mark - CAAnimationDelegate- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {    if ([anim isEqual:[self.animationView.layer animationForKey:@"anitio"]]) {        <#statements#>    }}

这儿基本上经常用的CAAnimation的属性就讲解完了,更多的实用。

常见的动画组合大部分是一个是同时执行:如,同时进行着缩放和位移,这个时候就需要用到CAAnimationGroup
如下代码:

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];    animation.fromValue = @(100);    animation.toValue = @(300);//    animation.duration = 1.0;//    animation.fillMode = kCAFillModeForwards;//    animation.removedOnCompletion = NO;    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];    scaleAnimation.fromValue = @(1.0);    scaleAnimation.toValue = @(0.5);//    scaleAnimation.duration = 1.0;//    scaleAnimation.fillMode = kCAFillModeForwards;//    scaleAnimation.removedOnCompletion = NO;    CAAnimationGroup *grop = [CAAnimationGroup animation];    grop.animations = @[animation,scaleAnimation];    grop.duration = 1.0;    grop.fillMode = kCAFillModeForwards;    grop.removedOnCompletion = NO;    [self.animationView.layer addAnimation:grop forKey:@"anitio"];

这儿要注意的是虽然说animationscaleAnimation都可以设置duration,fillMode,removeOnCompletion,但是最终的效果是以grop设置的为主,如果不设置,会使用默认的值。

第二种动画组合是:如:先进行位移,位移结束之后进行缩放。
这个时候就需要上面介绍CAAnimationDelegate来处理
代码如下:

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];    animation.fromValue = @(100);    animation.toValue = @(300);    animation.duration = 1.0;    animation.fillMode = kCAFillModeForwards;    animation.removedOnCompletion = NO;    animation.delegate = self;    [self.animationView.layer addAnimation:animation forKey:@"anitio”];
#pragma mark - CAAnimationDelegate- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {    if ([anim isEqual:[self.animationView.layer animationForKey:@"anitio"]]) {        CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];        scaleAnimation.fromValue = @(1.0);        scaleAnimation.toValue = @(0.5);        scaleAnimation.duration = 1.0;        scaleAnimation.fillMode = kCAFillModeForwards;        scaleAnimation.removedOnCompletion = NO;        [self.animationView.layer addAnimation:scaleAnimation forKey:@"scalAnimation"];    }}

到这儿为止,都是一些简单的动画组合,只要细心,基本上可以满足大多数动画需求,但是还是会有其他更为复杂的动画,上面介绍的可能就不满足或者说能满足,但是代码量很大。这儿就介绍一些其他处理方式:
1.CAShapeLayer + UIBezierPath ;如:需要一个动画,三角形变化成为圆形,循环变化。

栗子如下:这儿只是提供思路,和简单的代码实现,如需要实现真实的场景,需要多花点心思来书写UIBezierPath

    UIBezierPath *triangle_path = [UIBezierPath bezierPath];    [triangle_path moveToPoint:CGPointMake(50, 20)];    [triangle_path addLineToPoint:CGPointMake(30, 70)];    [triangle_path addLineToPoint:CGPointMake(80, 70)];    [triangle_path closePath];    UIBezierPath *cycle_path = [UIBezierPath bezierPath];    [cycle_path addArcWithCenter:CGPointMake(50, 50) radius:30 startAngle:0 endAngle:M_PI * 2 clockwise:YES];    self.shaperLayer.path = triangle_path.CGPath;    CABasicAnimation *shaperAnimation = [CABasicAnimation animationWithKeyPath:@"path"];    shaperAnimation.fromValue = (__bridge id _Nullable)(triangle_path.CGPath);    shaperAnimation.toValue  = (__bridge id _Nullable)(cycle_path.CGPath);    shaperAnimation.duration  = 0.5;    shaperAnimation.fillMode  = kCAFillModeForwards;    shaperAnimation.removedOnCompletion = NO;    [self.shaperLayer addAnimation:shaperAnimation forKey:@"shapeAnimation”];

2.重绘layer。动画的本质就是根据一个输入,作用出来一些过渡效果,展示给用户看。屏幕刷新频率是60帧/1秒
所以只要有能力可以根据算法写一些关键帧的参数,自己重绘layer来达到自己想要的动画效果,据我所知,谷歌给的动画Pop sdk,就是用CADisplayLink + CAShapeLayer 绘制而成;

这篇文章也是核心动画的一些个概念,介绍了一些简单的用法和技巧,完了之后我重现一下现有APP上面的一些好看的动画,也是基于上面概念的应用。

原创粉丝点击