您的位置:首页 > 移动开发 > IOS开发

iOS 动画开发之Core Animation

2015-12-30 21:16 399 查看
简介
操作对象:CALayer实例
操作方法:配置一些动画参数,然后调用动画开始的方法
框架优势:简单的API,不会像OpenGL那么变态,不会占用CPU资源,即不会影响APP的主线程处理

基础部分:

Core Animation 改变的大部分都是应用中可见的对象的属性,大部分的操作就是指定的属性值之间的变化。
属性有:
1.Geometry Properties

bounds

position

frame (computed from the bounds and position and is not animatable)

anchorPoint

cornerRadius

transform

zPosition
iOS Note: The cornerRadius property is supported only in iOS 3.0 and later.

2.Background Properties:

backgroundColor

backgroundFilters (not supported in iOS)
Platform Note: In iOS, the backgroundFilters property is exposed in the CALayer class but the filters you assign to this property are ignored.

3.Layer Content

contents

contentsGravity

masksToBounds

(Content 会被渲染在Background Color 之上,Content可以是图片或者是直接通过 Quartz, Metal, OpenGL, and Quartz Composer 框架种的接口直接描绘出来)

4.Sublayers Content

sublayers

masksToBounds(是否根绝Parent Layer 的大小裁剪)

sublayerTransform

5.Border Attributes
•borderColor
•borderWidth

6.Filters Property


filters

compositingFilter
Note:之后OS X支持

7.Shadow Properties

shadowColor

shadowOffset

shadowOpacity

shadowRadius

shadowPath

8.Opacity Property

opacity

9.Mask Properties

mask

在Core Animation框架中的Layer是被展现在3D空间中的2D平面
那么所谓的Layer就是抓取App展现的当前可见的内容,并把这些东西缓存在一个bitmap里,专业称之为“backing store”
既然提到了空间,那么就要说说坐标系的问题:

Layer使用了两种类型的坐标系:
point-based coordinate systems
主要就是为了指定一些直接映射到屏幕上的值,比如说 position

unit coordinate systems
主要是指定那些跟屏幕坐标没有太多关系的值,比如说,anchor point

其中的Anchor Point对于变换来说非常的重要,因为顾名思义,就是锚点,定在某个点上,就要依据这个点来做变换,特别是旋转
而且Anchor Point 直接影响了几何位置的计算
关于变换的动画其实就是(rotate,scale,translate),通过Layer的transform属性,并通过CATransform3D相关的函数来进行变换

讲了这么多,应该认识一下在一个Window中的Layer Tree

An app using Core Animation has three sets of layer objects. Each set of layer objects has a different role in making the content of your app appear onscreen:

Objects in the model layer tree (or simply “layer tree”) are the ones your app interacts with the most. The objects in this tree are the model objects that store the target values for any animations. Whenever you change the property of a layer, you use one
of these objects.

Objects in the presentation tree contain the in-flight values for any running animations. Whereas the layer tree objects contain the target values for an animation, the objects in the presentation tree reflect the current values as they appear onscreen. You
should never modify the objects in this tree. Instead, you use these objects to read current animation values, perhaps to create a new animation starting at those values.

Objects in the render tree perform the actual animations and are private to Core Animation.
上图:
如果你想访问到正在进行动画的Layer的信息,你就必须要通过presentLayer来获取即时的属性,如果你要是通过layer属性获取的不是动画中得对象的值。

重点解惑:
View和Layer的关系
Layer只是为了给View提供框架的,它不能处理事件,不能参与响应链,不能Draw内容,但是Layer可以给你的View增加更炫的效果
除了与View关联的Layer之外,也可以创建不与任何View相关联的Layer,然后将其add到任意的Layer层中,最常用的优化策略之一就是:一个图片被很多地方都使用,为了优化资源,可以创建一个单独的Layer,将图片设置为Layer的content,然后将Layer add到需要使用图片的地方。

另外,如果是OS X,如果想使用Layer做动画,是必须要声明App支持Layer,具体做法:
In iOS apps, Core Animation is always enabled and every view is backed by a layer. In OS X, apps must explicitly enable Core Animation support by doing the following:

Link against the QuartzCore framework. (iOS apps must link against this framework only if they use Core Animation interfaces explicitly.)

Enable layer support for one or more of your a target="_self" NSView/a objects by doing one of the following:

In your nib files, use the View Effects inspector to enable layer support for your views. The inspector displays checkboxes for the selected view and its subviews. It is recommended that you enable layer support in the content view of your window whenever possible.

For views you create programmatically, call the view’s a target="_self" setWantsLayer:/a method and pass a value of YES to indicate that the view should use layers.

接下来就将一些详细的东西:
Changing the Layer Object Associated with a View

Listing 2-1 Specifying the layer class of an iOS view
+ (Class) layerClass {
return [CAMetalLayer class];
}
因为CoreAnimation为了某些特定的场景支持,需要改变Layer对象,比如


Your view draws content using Metal or OpenGL ES, in which case you would use a CAMetalLayer or CAEAGLLayer object.

There is a specialized layer class that offers better performance.

You want to take advantage of some specialized Core Animation layer classes, such as particle emitters or replicators.
在OS X中就不太一样:

// Create myView...

[myView setWantsLayer:YES];
CATiledLayer* hostedLayer = [CATiledLayer layer];
[myView setLayer:hostedLayer];

// Add myView to a view hierarchy.

那么CoreAnimation提供的特定场景的Layer类有:

Providing a Layer’s Contents
1.使用图片(注意contentScale属性的专为Retain 显示屏而设置的,默认不是)
2.使用委托代理的方式,就需代理方实现以下
Listing 2-3 Setting the layer contents directly
- (void)displayLayer:(CALayer *)theLayer {

// Check the value of some state property

if (self.displayYesImage) {

// Display the Yes image

theLayer.contents = [someHelperObject loadStateYesImage];

}

else {

// Display the No image

theLayer.contents = [someHelperObject loadStateNoImage];

}

}
或者是:
Listing 2-4 Drawing the contents of a layer
- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext {

CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
CGPathAddCurveToPoint(thePath,
NULL,
15.f,250.0f,
295.0f,250.0f,
295.0f,15.0f);

CGContextBeginPath(theContext);
CGContextAddPath(theContext, thePath);
CGContextSetLineWidth(theContext, 5);
CGContextStrokePath(theContext);
// Release the path
CFRelease(thePath);
}
3.通过继承CALayer
When subclassing, you can use either of the following techniques to draw your layer’s content:

Override the layer’s display method and use it to set the contents property of the layer directly.

Override the layer’s drawInContext: method and use it to draw into the provided graphics context.

Adding Custom Properties to a Layer
因为CAAnimation和CALayer类扩展了 KVC。所以可以给Layer自定义属性
Ex:
[theLayer setValue:[NSNumber numberWithInteger:50] forKey:@"someKey"];
someKeyValue = [theLayer valueForKey:@"someKey"];

接下来就说CoreAnimation怎么让内容动起来

CAAnimation是顶层父类,一般不用
CATransition类,主要做转场效果的
CAPropertyAnimation也是一个抽象类,一般使用其两个子类:
CABasicAnimation: 简单的为图层的属性提供修改
CAKeyframeAnimation:可以指定的图层属性的关键路径动画,包括动画的每个阶段的价值,以及关键帧时间和计时功能的一系列值
这个类提到的关键路径就是字符串编码的属性路径,例如,rotation.x,size.width
KeyPath支持的数据类型有:CGPoint, CGRect, CGSize, CATransform3D
CATransform3D Key Paths:

Ex:
[myLayer setValue:[NSNumber numberWithFloat:10.0] forKeyPath:@"transform.translation.x"];
CGPoint Key Paths:
CGSize Key Paths
CGRect Key Paths

Ex:改变bounds的属性可以使用以下代码
[myLayer setValue:[NSNumber numberWithFloat:10.0] forKeyPath:@"bounds.size.width”];
CASpringAnimation(iOS9):弹簧效果的动画
动画也可以组合,但是需通过CAAnimationGroup类将其他动画添加到自身,然后在赋予Layer对象

一旦动画启动了,怎么终止呢?
1.如果是使用了addAnimation:forKey:,那可以使用removeAnimationForKey来终止动画
2.也可以使用removeAllAnimations停止所有的动画

要想检测到动画进行的状态,可以通过以下方式:
1.对当前的动画transaction调用setCompletionBlock:
2.给CAAnimation对象设置delegate,然后实现animationDidStart: and animationDidStop:finished:

如何暂停和恢复动画呢?
可以让Layer采用CAMediaTiming 协议,然后向下面这样做:
-(void)pauseLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}

-(void)resumeLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}

CADisplaylink
  CADisplayLink的使用有点像NSTimer,本身也是一个定时器对象,只不过它的用途更专一,只用于界面显示帧更新相关的操作,并且通常不允许子类化。
CAMediaTimingFunction
  该类定义了一个动画的执行步调,目前Core Animation提供有kCAMediaTimingFunctionLinear、kCAMediaTimingFunctionEaseIn、kCAMediaTimingFunctionEaseOut、kCAMediaTimingFunctionEaseInEaseOut四种,当然我们也可以定制自己想要的执行步调。
Layer的先后顺序的调整(类似View的操作):
Adding layers
addSublayer:
Inserting layers
insertSublayer:above:
insertSublayer:atIndex:
insertSublayer:below:
Removing layers
removeFromSuperlayer
Exchanging layers
replaceSublayer:with:
Layer之间的坐标系转换
convertPoint:fromLayer:
convertPoint:toLayer:
convertRect:fromLayer:
convertRect:toLayer:

接下来说一点高阶:
通过Transactions改变动画参数
这需要知道,CAAnimation的每一个改变其实都是一个transaction的一部分
Creating an explicit transaction
[CATransaction begin];
theLayer.zPosition=200.0;
theLayer.opacity=0.0;
[CATransaction commit];
Changing the default duration of animations
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:10.0f] forKey:kCATransactionAnimationDuration];
// Perform the animations
[CATransaction commit];
另外CATransaction支持嵌套

最高阶:改变Layer的默认行为
1.需要自定义action 对象,必须要遵循CAAction 协议,然后实现runActionForKey:object:arguments:
2.第一步创建的action对象要装在Layer对象上,因为,一个action被执行之前,Layer对象需要去找到与之相对应的action去执行,这个时候上一步提到的kay
就非常的重要
Ex:
Providing an action using a layer delegate object
- (id<CAAction>)actionForLayer:(CALayer *)theLayer forKey:(NSString *)theKey {
CATransition *theAnimation=nil;
if ([theKey isEqualToString:@"contents"]) {
theAnimation = [[CATransition alloc] init];
theAnimation.duration = 1.0;
theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
theAnimation.type = kCATransitionPush;
theAnimation.subtype = kCATransitionFromRight;
}
return theAnimation;
}

临时禁用Action对象的话,可以使用CATransaction 类:
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
[aLayer removeFromSuperlayer];
[CATransaction commit];
以上基本上讲完了CoreAnimation的大致框架,其实就是API的调用,都是更加上层的封装
如果还想学习更加详细的,可以参阅:CocoaChina动画专栏
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: