Core Animation

本文为读书笔记: iOS Core Animation: Advanced Techniques
1.实际上layer才是真正用来在屏幕上显示和做动画,UIView仅仅是对它的一个封装,提供了一些iOS类似于处理触摸的具体功能,以及Core Animation底层方法的高级接口。

2.我们已经证实了图层不能像视图那样处理触摸事件,那么他能做哪些视图不能做的呢?这里有一些UIView没有暴露出来的CALayer的功能:

  • 阴影 、圆角、带颜色的边框
  • 3D变换
  • 非矩形范围
  • 透明遮罩
  • 多级非线性动画
CALayer 属性 属性类型 作用
contents id 设置图片
contentsGravity NSString 设置图片展示,类似于viewcontentMode

3.contents

id意味着给contents赋任何值编译都可以通过,但是,在实践中,如果你给contents赋的不是CGImage,那么你得到的图层将是空白的。contents这个奇怪的表现是由Mac OS的历史原因造成的。它之所以被定义为id类型,是因为在Mac OS系统上,这个属性对CGImageNSImage类型的值都起作用。
使用 :layer.contents = (__bridge id)image.CGImage;

4.contentsGravity
UIViewcontentMode,对这些属性的操作其实是对对应图层的操作,contentsGravity就是图层的contentMode


/** Layer `contentsGravity' values. **/

CA_EXTERN NSString * const kCAGravityCenter

CA_EXTERN NSString * const kCAGravityTop

CA_EXTERN NSString * const kCAGravityBottom

CA_EXTERN NSString * const kCAGravityLeft

CA_EXTERN NSString * const kCAGravityRight

CA_EXTERN NSString * const kCAGravityTopLeft

CA_EXTERN NSString * const kCAGravityTopRight

CA_EXTERN NSString * const kCAGravityBottomLeft

CA_EXTERN NSString * const kCAGravityBottomRight

CA_EXTERN NSString * const kCAGravityResize

CA_EXTERN NSString * const kCAGravityResizeAspect

CA_EXTERN NSString * const kCAGravityResizeAspectFill

5.contentsScale这个设置图片的每个点1个像素或者两个像素
使用 :
layer.contentsScale = image.scale;
或者
layer.contentsScale = [UIScreen mainScreen].scale;
6.contentsRect 可以用来作拼合图片(一般APP估计不会使用)
7.CALayer给不同坐标系之间的图层转换提供了一些工具类方法:

- (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer; 
- (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer; 
- (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
 - (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;

8.阴影效果

  • shadowOpacity : 是一个必须在0.0(不可见)和1.0(完全不透明)之间的浮点数。
  • shadowColor : 属性控制着阴影的颜色,和borderColorbackgroundColor一样,它的类型也是CGColorRef。阴影默认是黑色。
  • shadowOffset属性控制着阴影的方向和距离。它是一个CGSize的值,宽度控制这阴影横向的位移,高度控制着纵向的位移。shadowOffset的默认值是 {0, -3},意即阴影相对于Y轴有3个点的向上位移(以为shadow最早出现在MacOS,在MacOS上坐标轴和iOS是相反的)。
  • shadowPath : 如果事先知道阴影的形状,可以设置shadowPath来提高性能。

9.opacity相当于viewalpha

10.layer.shouldRasterize
这是由透明度的混合叠加造成的,当你显示一个50%透明度的图层时,图层的每个像素都会一半显示自己的颜色,另一半显示图层下面的颜色。这是正常的透明度的表现。但是如果图层包含一个同样显示50%透明的子图层时,你所看到的视图,50%来自子视图,25%来了图层本身的颜色,另外的25%则来自背景色。
在我们的示例中,按钮和表情都是白色背景。虽然他们都是50%的可见度,但是合起来的可见度是75%,所以标签所在的区域看上去就没有周围的部分那么透明。所以看上去子视图就高亮了,使得这个显示效果都糟透了。
解决办法:

bottomView.layer.shouldRasterize = YES;  
bottomView.layer.rasterizationScale = [UIScreen mainScreen].scale;

11.CGAffineTransform

  • 仿射的意思是无论变换矩阵用什么值,图层中平行的两条线在变换之后任然保持平行
  • 如果需要混合两个已经存在的变换矩阵,就可以使用如下方法,在两个变换的基础上创建一个新的变换:
CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);

12.CATransform3Dm34元素,用来做透视
详见

- (void)viewDidLoad {    [super viewDidLoad];  
  //create a new transform    
CATransform3D transform = CATransform3DIdentity;   
 //apply perspective  
  transform.m34 = - 1.0 / 500.0;  
  //rotate by 45 degrees along the Y axis  
  transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);   
 //apply to layer    
self.layerView.layer.transform = transform; }
  1. 创建一个3D的正方体](https://zsisme.gitbooks.io/ios-/content/chapter5/solid-objects.html))
    14.Core Graphics直接向原始的CALyer的内容中绘制一个路径,相比直下,使用CAShapeLayer有以下一些优点:
  • 渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
  • 高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
  • 不会被图层边界剪裁掉。一个CAShapeLayer可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉(如我们在第二章所见)。
  • 不会出现像素化。当你给CAShapeLayer做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。

15.UILabel : 借助图层代理直接将字符串使用Core Graphics写入图层的内容
16.宿主图层 : 指的是viewlayer,既self.view.layer,可以通过下面的方法改变


+ (Class)layerClass

{

    return [CATextLayer class];

}

17.CATextLayer替换 UILabal](https://zsisme.gitbooks.io/ios-/content/chapter6/CATextLayer.html))

18.CATransformLayer :创建一个立方体图层
19.CAGradientLayer

  • colors : 保存的各种颜色
  • locations : 颜色的作用范围,这个范围数组需要个颜色数组保持相同 , 当只有两个颜色的时候设置gradientLayer.locations = @[@0,@1];是均分两个视图
  • startPoint,开始的点,(0 , 0)代表左上角
  • endPoint,结束的店,(1 , 1)代表右下角

20.CATiledLayer : 把一个大图裁剪成小图并加载,一般用在地图,或者加载大的图片.

  1. Transactions(事务) : 实际上是Core Animation用来包含一系列属性动画集合的机制,任何用指定事务去改变可以做动画的图层属性都不会立刻发生变化,而是当事务一旦提交的时候开始用一个动画过渡到新值。
  • begin : 开始
  • commit : 结束
  • + (void)setCompletionBlock:(nullable void (^)(void))block; : 代码完成块

例1

- (void)viewDidLoad

{

    [super viewDidLoad];    

    self.colorLayer = [CALayer layer];

    self.colorLayer.frame = CGRectMake(0.0f, 0.0f, 150.0f, 150.0f);

    self.colorLayer.backgroundColor = [UIColor blueColor].CGColor;

    //add it to our view

    [self.containerView.layer addSublayer:self.colorLayer];

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{
   //begin a new transaction

    [CATransaction begin];

    //set the animation duration to 1 second

    [CATransaction setAnimationDuration:5.0];

    //randomize the layer background color

    CGFloat red = arc4random() / (CGFloat)INT_MAX;

    CGFloat green = arc4random() / (CGFloat)INT_MAX;

    CGFloat blue = arc4random() / (CGFloat)INT_MAX;

    self.colorLayer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;

    //commit the transaction

    [CATransaction commit];

}

例2

- (void)viewDidLoad{    [super viewDidLoad];    //create sublayer    self.colorLayer = [CALayer layer];    self.colorLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);    self.colorLayer.backgroundColor = [UIColor blueColor].CGColor;    //add a custom action    CATransition *transition = [CATransition animation];    transition.type = kCATransitionPush;    transition.subtype = kCATransitionFromLeft;    self.colorLayer.actions = @{@"backgroundColor": transition};    //add it to our view    [self.layerView.layer addSublayer:self.colorLayer];}- (IBAction)changeColor{    //randomize the layer background color    CGFloat red = arc4random() / (CGFloat)INT_MAX;    CGFloat green = arc4random() / (CGFloat)INT_MAX;    CGFloat blue = arc4random() / (CGFloat)INT_MAX;    self.colorLayer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;}

22.隐式动画是如何实现的

  • 图层首先检测它是否有委托,并且是否实现CALayerDelegate
    协议指定的-actionForLayer:forKey
    方法。如果有,直接调用并返回结果。
  • 如果没有委托,或者委托没有实现-actionForLayer:forKey
    方法,图层接着检查包含属性名称对应行为映射的actions
    字典。
  • 如果actions字典
    没有包含对应的属性,那么图层接着在它的style
    字典接着搜索属性名。
  • 最后,如果在style
    里面也找不到对应的行为,那么图层将会直接调用定义了每个属性的标准行为的-defaultActionForKey:
    方法。

23.CATransition响应CAAction协议,并且可以当做一个图层行为.行为通常是一个被Core Animation隐式调用的显式动画对象。

24.presentationLayer : 呈现图层 ,用户真正看到的图层(相当于View)
modelLayer : 图层模型 (相当于Model)
Core Animation : 相当于控制器

大多数情况下,你不需要直接访问呈现图层,你可以通过和模型图层的交互,来让Core Animation更新显示。两种情况下呈现图层会变得很有用,一个是同步动画,一个是处理用户交互。

  • 如果你在实现一个基于定时器的动画(见第11章“基于定时器的动画”),而不仅仅是基于事务的动画,这个时候准确地知道在某一时刻图层显示在什么位置就会对正确摆放图层很有用了。
  • 如果你想让你做动画的图层响应用户输入,你可以使用-hitTest:方法(见第三章“图层几何学”)来判断指定图层是否被触摸,这时候对呈现图层而不是模型图层调用-hitTest:会显得更有意义,因为呈现图层代表了用户当前看到的图层位置,而不是当前动画结束之后的位置。

25.缓冲函数CAMediaTimingFunction
自定义缓冲函数

+ (instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;

- (instancetype)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
  • 那么该如何使用缓冲方程式呢?
    首先需要设置CAAnimation的timingFunction属性,是CAMediaTimingFunction类的一个对象。如果想改变隐式动画的计时函数,同样也可以使用CATransaction+setAnimationTimingFunction:方法。

26.RunLoop

NSDefaultRunLoopMode - 标准优先级
NSRunLoopCommonModes- 高优先级
UITrackingRunLoopMode- 用于UIScrollView和别的控件的动画

CADisplayLink : 屏幕更新执行一次刷新一次

self.timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(step:)]; 
[self.timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 
[self.timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode];

NSTimer :标准的时间


self.timer = [NSTimer timerWithTimeInterval:1/60.0                                 target:self                               selector:@selector(step:)                               userInfo:nil                                repeats:YES];[[NSRunLoop mainRunLoop] addTimer:self.timer                          forMode:NSRunLoopCommonModes];

你可能感兴趣的:(Core Animation)