Core Animation和CALayer

Animation Core想必大家都比较熟悉,是苹果一套针对动画效果的牛逼API,直接作用在layer上。今天打算扯扯这套API的某些细节,既然是作用在layer上那咱就先从layer开始扯起……

一、CALayer

1.1 什么是CALayer

每个能在界面上看到的ui控件,其实都是因为这些ui控件里面有个layer层。这个层就是CALayer类,它有个很牛逼的方法:- (void)drawInContext:(CGContextRef)ctx;从这就能看出,当UIView需要显示的时候就会调用它进行绘图,绘图完毕后系统会把这个层拷贝到屏幕上就会被你look到。它还有个牛逼的方法:- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key;这个就是跟Animation Core相关的方法,咱一会在看

1.2 CALayer怎么用?(CALayer是定义在QuartzCore框架下的)

/** Layer creation and initialization. **/

+ (instancetype)layer;

/* The designated initializer. */

- (instancetype)init;

/* This initializer is used by CoreAnimation to create shadow copies of
 * layers, e.g. for use as presentation layers. Subclasses can override
 * this method to copy their instance variables into the presentation
 * layer (subclasses should call the superclass afterwards). Calling this
 * method in any other situation will result in undefined behavior. */

- (instancetype)initWithLayer:(id)layer;
View Code

CALayer提供了这么多创建的方法。一个UIView默认会有一个Layer,但你可以手动添加其他的layer,可以设置或修改layer的属性改变起现实的样子。这些基础的东西直接贴段代码以示说明

CALayer *customLayer=[CALayer layer];
    customLayer.bounds=CGRectMake(10, 10, 100, 100);
    
    customLayer.backgroundColor=[UIColor orangeColor].CGColor;
    
    //设置层中心点的位置(默认情况下中心点位置为0,0)
    customLayer.position=CGPointMake(100, 100);
    
    //设置圆角半径
    customLayer.cornerRadius=10;
    [self.view.layer addSublayer:customLayer];
View Code

也可以让我们自己创建的层现实具体的内容,比如一张图片(设置它的contents属性)customLayer.contents=(id)[UIImage imageNamed:@"fish"].CGImage;

CGColorRef和UIColor以及CGImageRef和UIImage

上文已经提醒过CALayer是定义在QuartzCore框架里,而CGImageRef、CGColor是定义在CoreGraphics框架里的,UIColor、UIImage是定义在UIKit框架里的。QuartzCore和CoreGraphics是可以跨平台的,在Mac和iOS上都能使用,但UIKit只能在iOS中使用,故而为了可移植性,QuartzCore只能使用CGImageRef、CGColor。undenstand?

二、Core Animation

2.1 Core Animation基本使用

 

UIView *myView=[[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    myView.layer.position=CGPointMake(100, 100);
    myView.backgroundColor=[UIColor orangeColor];
    self.myView=myView;
    [self.view addSubview:myView];
    
    CABasicAnimation *anim=[CABasicAnimation animationWithKeyPath:@"position"];
    anim.duration=1.5;
    anim.fromValue=[NSValue valueWithCGPoint:CGPointMake(50, 80)];
    anim.toValue=[NSValue valueWithCGPoint:CGPointMake(300, 350)];
    anim.delegate=self;
    anim.removedOnCompletion=NO;
    anim.fillMode=kCAFillModeForwards;
    [myView.layer addAnimation:anim forKey:@"translate"];
View Code

 

两个需要注意的属性:

  1、toValue表示移动到某个位置,如果换成byValue就成了移动了多少位置

  2、默认情况下,动画执行完毕后会回到初始的位置,为了保持移动后的状态,需要设置

  anim.removedOnCompletion=NO;

     anim.fillMode=kCAFillModeForwards;

CABasicAnimation是CAPropertyAnimation的自类,CAPropertyAnimation又是CAAnimation的子类,在CAAnimation中,在这个父类中有个代理其中有两个代理方法

- (void)animationDidStart:(CAAnimation *)anim;

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

可以用来监控运动的完成过程。在animationDidStop:方法中打印uiview当前的位置,可以看到与运动前的位置并没有改变。这是为什么呢?

2.2 Core Animation维护两个layer

这里需要说明的是当你把一个动画添加到layer时,是不直接修改它的属性的

Core Animation维护了两个平行的layer层次结构:model layer tree和presentation layer tree(模型层树和表示层书树)。前者中的 layers 反映了我们能直接看到的 layers 的状态,而后者的 layers 则是动画正在表现的值的近似。

/* Returns a copy of the layer containing all properties as they were

 * at the start of the current transaction, with any active animations

 * applied. This gives a close approximation to the version of the layer

 * that is currently displayed. Returns nil if the layer has not yet

 * been committed.

 *

 * The effect of attempting to modify the returned layer in any way is

 * undefined.

 *

 * The `sublayers', `mask' and `superlayer' properties of the returned

 * layer return the presentation versions of these properties. This

 * carries through to read-only layer methods. E.g., calling -hitTest:

 * on the result of the -presentationLayer will query the presentation

 * values of the layer tree. */

 

- (id)presentationLayer;

/* When called on the result of the -presentationLayer method, returns

 * the underlying layer with the current model values. When called on a

 * non-presentation layer, returns the receiver. The result of calling

 * this method after the transaction that produced the presentation

 * layer has completed is undefined. */

 - (id)modelLayer;

上面说到默认情况下动画结束后会被移除,也就是说动画不会在超出起持续时间后还修改presentation layer,而是会彻底移除,一旦动画被移除presentation layer将回到model layer的值,并且动画过程中我们并未修改过position的值,所以你看到它又回到了原来的位置

除了设置fillMode=kCAFillModeForward强制其留在最终状态并设置removedOnCompletion为NO以防止动画被自动移除外,还可以干脆就设置uiview的position为动画停止的position。

还有一点不是很多人了解的是:如果将已完成的动画保持在layer上时,会造成额外的开销,因为渲染器会去进行额外的绘画工作。庆幸的是我们创建的动画对象被添加到layer时立刻就赋值了一份。这个特性在多个view中重用动画时非常有用。

待续……

 

posted @ 2015-03-13 16:36  luseike  阅读(284)  评论(0编辑  收藏  举报