现在的位置: 首页 > 综合 > 正文

核心动画学习笔记

2013年04月23日 ⁄ 综合 ⁄ 共 5676字 ⁄ 字号 评论关闭

1、核心动画框架

page7image5800


  • CAScrollLayer  CALayer 的子类,简化显示图层的一部分内容。CAScrollLayer 对象的滚动区域的范围在它的子图层里面定义。CAScrollLayer
    提供键盘或鼠标事件处理,也不提供可见的滚动条。
  • CATextLayer 可以方便的从字符串或字符串的内容创建一个图层类的内容。 
  • CATiledLayer 允许递增的显示大而复杂的图片。
  • CAEAGLLayer 提供了一个OpenGLES渲染环境。
  • CATransition 提供了一个图层变化的过渡效果,它能影响图层的整个内容。 动画进行的时候淡入淡出(fade)、推(push)、显露(reveal)图层的内容。这些过渡效 果可以扩展到你自己定制的 Core Image 滤镜(CIFilter,ios暂不可用)。
  • CAAnimationGroup 允许一系列动画效果组合在一起,并行显示动画。
  • CAPropertyAnimation 是一个抽象的子类,它支持在动画的显示图层的关键路径中指定的属性
  • CABasicAnimation 简单的对图层的属性提供修改。
  • CAKeyframeAnimation 支持关键帧动画,你可以指定图层属性的关键路径动画,包括动画在每个阶段的值,以及关键帧时间和计时功能的一系列值。在
    动画运行时,每个值被特定的插入值替代



CAConstraint  类是一个布局管理器,用于描述层的几何属性(左,右,顶部或底部的边缘或水平或垂直中心)的关系。

CATransaction 在核心动画里面负责协调多个动画原子更新显示操作,图层的动画属性的每一个修改必然是事务的一部分。
隐式事务和显式事务
在图层的动画属性被一个线程修改,同时该线程下次迭代的时候自动提交该修改的时候隐式事务自动创建。显式事务 发生在程序在修改动画属性之前给 CATransaction 发送了一个开始消息,在动画属性
修改之后提交该消息。
2、图层, layer

图层的 anchorPoint 属性是一个 CGPoint 值,它指定了一个基于图层 bounds 的符
合位置坐标系的位置。锚点(anchor point)指定了 
bounds 相对于 position(相当于view的center) 的值,同时也作为变换时候的支点。锚点使用单元空间坐标系表示,(0.0,0.0)点接近图层
的原点,而(1.0,1.0)是原点的对角点


page15image5616
page16image7568
3、变换矩阵
CATransform3D 变换矩阵 4*4
CGAffineTransform 仿射矩阵 [ a b c d tx ty ]

核心动画扩展了键-值编码协议,允许通过关键路径获取和设置一个图层的 CATransform3D 矩阵的值。表 4 描述了图层的 transform 和 sublayerTransform 属性的
相应关键路径。


page19image25824
Table 4 CATransform3D key paths

你不可以通过Objective-C 2.0的属性方法来指定一个结构字段的关键路径如下的代码是无法正常执行的::
 myLayer.transform.rotation.x=0;

替换的办法是,你必须通过 setValue:forKeyPath:或者 valueForKeyPath:方法, 具体如下:

 [myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];
4、每个UIView会自动创建一个CALayer类的实例,然后赋值给layer属性
maskToBounds属性决定子图层是否相对于父图层裁剪

5、给CALayer 提供内容

通过delegat: // 一般是layer所在的view
displayLayer: 或 drawLayer:inContext:

触发上面的回调
setNeedsDisplay、setNeedsDisplayInRect:、或者把图层的needsDisplayOnBoundsChange属性设置为YES。


- (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,
                           
                           [[theLayer valueForKey:@"lineWidth"] floatValue]);
     CGContextStrokePath(theContext);
     
     // release the path
     CFRelease(thePath);
}

6、修改图层内容位置
layer的contentsGravity属性


7、图层Action
当一个行为触发器发生的时候,图层的actionForKey:方法被调用。此方法返回一个行为对象(满足CAAction协议的对象),对应的标识符作为参数,或如果行为对象不存在的话返回nil。

    当CALayer为一个标识符实现的actionForKey:方法被调用的时候,以下的搜索模式将会被用到:

  1. 如果一个图层有委托,那方法actionForLayer:forKey:的实现将会被调用,把图层和行为标识符作为参数。委托的actionForLayer:forKey:的实现需要响应如下:

    • 返回一个行为标识符对应的行为对象。
    • 返回nil,当无法处理行为标识符的时候。
    • 返回NSNull,当无法处理行为标识符,而且搜索需要被终止的时候。
  2. 图层的actions字典被搜索以便找到一个和行为标识符对应的对象。
  3. 图层的style属性被搜索以便找到一个包含行为标识符的actions字典。
  4. 图层类发生一个defaultActionForKey:的消息。它将会返回一个和标识符对应的行为对象,如果不存在的话则返回nil。
通常行为对象是CAAnimation的子类实例,它实现了CAAction协议。然而你也可以返回任何实现了CAAction协议的类对象。当实例收到runActionForKey:object:arguments:的消息时,它需要执行相应的行为。

代码 1  runActionForKey:object:arguments: 的实现:启动动画

- (void)runActionForKey:(NSString *)key
                 object:(id)anObject
              arguments:(NSDictionary *)dict
{
     [(CALayer *)anObject addAnimation:self forKey:key];
}

重载隐式动画

通过插入一个CAAnimation的实例到style字典里面的actions的字典里面,通过实现委托方法actionForLayer:forKey:或者继承图层类并重载defaultActionForKey:方法返回一个相应的行为对象。
代码2的示例通过委托替换contents属性的隐式动画。
- (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;
}

代码3的示例使用actions字典模式禁用sublayers属性的默认动画。
// get a mutable version of the current actions dictionary
NSMutableDictionary *customActions=[NSMutableDictionary dictionaryWithDictionary:[theLayer actions]];

// add the new action for sublayers
[customActions setObject:[NSNull null] forKey:@"sublayers"];

// set theLayer actions to the updated dictionary 
theLayer.actions=customActions;

8、事务

 隐式事务

当图层树被没有获得事务的线程修改的时候将会自动创建隐式事务,当线程的运行循环(run-loop)执行下次迭代的时候将会自动提交事务。
重要:当在一个没有运行循环(runloop)的线程修改图层的属性的时候,你必须使用显式的事务,所以UI处理都必须放主线程。子线程默认都没有runloop的

显式事务

临时禁用图层的action

你可以在修改图层属性值的时候通过设置事务的kCATransactionDisableActions值为YES来暂时禁用图层的行为。在事务范围所作的任何更改也不会因此而发生的动画。
代码2显示了一个示例,当把aLayer从可视化图层树移除的时候禁用淡出动画。
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
                 forKey:kCATransactionDisableActions];
[aLayer removeFromSuperlayer];
[CATransaction commit];

你可以暂时改变响应改变图层属性的动画的时间,通过设置事务的kCATransactionAnimationDuration键的值为新的时间

代码4 中显示了一个嵌套两个事务的例子。最外层的事务设置隐式动画的时间为2秒,并设置图层的position属性值。内层的事务设置隐式动画的时间为5秒,并修改图层的opacity和zPosition属性值。
[CATransaction begin]; // outer transaction
 
// change the animation duration to 2 seconds
[CATransaction setValue:[NSNumber numberWithFloat:2.0f]
                forKey:kCATransactionAnimationDuration];
// move the layer to a new position
theLayer.position = CGPointMake(0.0,0.0);
 
[CATransaction begin]; // inner transaction
// change the animation duration to 5 seconds
[CATransaction setValue:[NSNumber numberWithFloat:5.0f]
                 forKey:kCATransactionAnimationDuration];
 
// change the zPosition and opacity
theLayer.zPosition=200.0;
theLayer.opacity=0.0;
 
[CATransaction commit]; // inner transaction
[CATransaction commit]; // outer transaction

9、键-值编码兼容的容器类

CALayer和CAAnimation都是键-值编码兼容的容器类,允许你修改属性键对应的值
为了给键提供默认值,你创建相应的子类,并重载defaultValueForKey:。子类实现相应的键参数检查并返回适当的默认值。清单1描述了一个实现defaultValueForKey:的例子,它给masksToBounds提供新的默认值。

+ (id)defaultValueForKey:(NSString *)key
{
    if ([key isEqualToString:@"masksToBounds"])
         return [NSNumber numberWithBool:YES];
 
    return [super defaultValueForKey:key]; 
}

抱歉!评论已关闭.