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;
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];
也可以让我们自己创建的层现实具体的内容,比如一张图片(设置它的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"];
两个需要注意的属性:
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中重用动画时非常有用。
待续……