CAAnimation核心動(dòng)畫

書籍是人類進(jìn)步的階梯

總覽思維導(dǎo)圖

核心動(dòng)畫思維導(dǎo)圖.png

一、圖層樹

1.1.contents

  • 簡(jiǎn)介:(id類型),雖然是id類型但如果給contents賦的不是CGImage,那么得到的圖層將是空白的。
    layer.contents = (__bridge id)image.CGImage;

  • 注意:在加載圖片時(shí)為了適應(yīng)視圖,我們一般這么處理:
    view.contentMode = UIViewContentModeScaleAspectFit;
    但在CALayer與contentMode對(duì)應(yīng)的屬性叫做contentsGravity
    self.layerView.layer.contentsGravity = kCAGravityResizeAspect;

1.2 contentsScale

  • 寄宿圖的像素尺寸和視圖大小的比例,默認(rèn)情況下它是一個(gè)值為1.0的浮點(diǎn)數(shù):當(dāng)用代碼來處理寄宿圖的時(shí)候,一定要記住要手動(dòng)的設(shè)置圖層的contentsScale屬性,否則,你的圖片在Retina設(shè)備上就顯示得不正確啦。代碼如下:
    layer.contentsScale = [UIScreen mainScreen].scale;

1.3 maskToBounds

  • UIView有一個(gè)叫做clipsToBounds的屬性可以用來決定是否顯示超出邊界的內(nèi)容,CALayer對(duì)應(yīng)的屬性叫做masksToBounds

1.4 contentsRect

  • 默認(rèn)的contentsRect是{0, 0, 1, 1},這意味著整個(gè)寄宿圖默認(rèn)都是可見的,如果設(shè)置{0,0,0.5,0.5},那只顯示左上角部分(整體的1/4部分)
contentsRect

1.5 contentsCenter

  • 其實(shí)是一個(gè)CGRect,它定義了一個(gè)固定的邊框和一個(gè)
    在圖層上可拉伸的區(qū)域。默認(rèn)情況下,contentsCenter是{0, 0, 1, 1},這意
    味著如果大?。ㄓ蒫onttensGravity決定)改變了,那么寄宿圖將會(huì)均勻地拉
    伸開。但是如果我們?cè)黾釉c(diǎn)的值并減小尺寸。我們會(huì)在圖片的周圍創(chuàng)造
    一個(gè)邊框。圖2.9展示了contentsCenter設(shè)置為{0.25, 0.25, 0.5, 0.5}的效果。


    contentsCenter.png

1.6 -drawRect:方法:

  • 當(dāng)視圖在屏幕上出現(xiàn)的時(shí)候 -drawRect:方法就會(huì)被自動(dòng)調(diào)用;
  • 調(diào)用了-setNeedsDisplay方法時(shí),-drawRect:方法會(huì)被調(diào)用;

二、圖層幾何學(xué)

2.1 frame、bounds、position

  • 當(dāng)對(duì)圖層做變換的時(shí)候,比如旋轉(zhuǎn)或者縮放,frame實(shí)際上代表了覆蓋在圖層旋轉(zhuǎn)之后的整個(gè)軸對(duì)齊的矩形區(qū)域,也就是說frame的寬高可能和bounds的寬高不再一致了


    frame

2.2 錨點(diǎn)anchorPoint

  • anchorPoint是用來移動(dòng)圖層的把柄。anchorPoint用單位坐標(biāo)來描述,也就是圖層的相對(duì)坐標(biāo),圖層左上角是{0, 0},右下角是{1, 1},因此默認(rèn)坐標(biāo)是{0.5, 0.5}

2.3zPosition

  • 在大多數(shù)情況下其實(shí)并不常用。zPosition最實(shí)用的功能就是改變圖層的顯示順序了。通過增加圖層的zPosition,就可以把圖層向相機(jī)方向前置,于是它就在所有其他圖層的前面了(或者至少是小于它的zPosition值的圖層的前面)。

2.4 -containsPoint

  • 接受一個(gè)在本圖層坐標(biāo)系下的CGPoint,如果這個(gè)點(diǎn)在圖層frame范圍內(nèi)就返回YES。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint point = [[touches anyObject] locationInView:self.view];
    point = [self.layerView.layer convertPoint:point fromLayer:self.view.layer];
    //get layer using containsPoint:
    if ([self.layerView.layer containsPoint:point]) {
        //convert point to blueLayer’s coordinates
        point = [self.blueLayer convertPoint:point fromLayer:self.layerView.layer];
        if ([self.blueLayer containsPoint:point]) {
          // your code
        } else {
           // your other code
        }
    }
}

2.5 -hitTest

  • 方法接受一個(gè)CGPoint類型參數(shù),而不是BOOL類型,它返回圖層本身,或者包含這個(gè)坐標(biāo)點(diǎn)的葉子節(jié)點(diǎn)圖層:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //get touch position
    CGPoint point = [[touches anyObject] locationInView:self.view];
    //get touched layer
    CALayer *layer = [self.layerView.layer hitTest:point];
    //get layer using hitTest
    if (layer == self.blueLayer) {
       // your code
    } else if (layer == self.layerView.layer) {
        // your other code
    }
}

三、專用圖層CALayer

3.1 CAShapeLayer

  • 使用CAShapeLayer的優(yōu)點(diǎn):
    • 渲染快速。CAShapeLayer使用了硬件加速,繪制同一圖形會(huì)比用Core Graphics快很多;
    • 高效使用內(nèi)存。一個(gè)CAShapeLayer不需要像普通CALayer一樣創(chuàng)建一個(gè)寄宿圖形,所以無論有多大,都不會(huì)占用太多的內(nèi)存;
    • 不會(huì)被圖層邊界剪裁掉。一個(gè)CAShapeLayer可以在邊界之外繪制。
    • 不會(huì)出現(xiàn)像素化。當(dāng)你給CAShapeLayer做3D變換時(shí),它不像一個(gè)有寄宿圖的普通圖層一樣變得像素化。

1.CAShapeLayer可以用來繪制所有能夠通過CGPath來表示的形狀。
2.CAShapeLayer屬性是CGPathRef類型

  • 繪制圓角:( 需求:三個(gè)圓角,一個(gè)直角)
CGRect rect = CGRectMake(50, 50, 100, 100);
CGSize radii = CGSizeMake(20, 20);
UIRectCorner corners = UIRectCornerTopRight | UIRectCornerBottomRight | UIRectCornerBottomLeft;
//create path
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:radii];

3.2 CATextLayer

  • CATextLayer也要比UILabel渲染得快得多。很少有人知道在iOS 6及之前的版本,UILabel其實(shí)是通過WebKit來實(shí)現(xiàn)繪制的,這樣就造成了當(dāng)有很多文字的時(shí)候就會(huì)有極大的性能壓力。
  • CATextLayer使用了Core text,并且渲染得非??臁?梢試L試封裝一個(gè)CATextLayer用于替換UILabel

UILabel的替代品

  • 使用CATextLayer來封裝一個(gè)UILabel的子類
#import "LayerLabel.h"
@implementation LayerLabel
+ (Class)layerClass
{
  //this makes our label create a CATextLayer //instead of a regular CALayer for its backing layer
  return [CATextLayer class];
}

- (CATextLayer *)textLayer
{
  return (CATextLayer *)self.layer;
}

- (void)setUp
{
  //set defaults from UILabel settings
  self.text = self.text;
  self.textColor = self.textColor;
  self.font = self.font;
//we should really derive these from the UILabel settings too
  //but that's complicated, so for now we'll just hard-code them
  [self textLayer].alignmentMode = kCAAlignmentJustified;
  
  [self textLayer].wrapped = YES;
  [self.layer display];
}

- (id)initWithFrame:(CGRect)frame
{
  //called when creating label programmatically
  if (self = [super initWithFrame:frame]) {
    [self setUp];
  }
  return self;
}

- (void)awakeFromNib
{
  //called when creating label using Interface Builder
  [self setUp];
}
- (void)setText:(NSString *)text
{
  super.text = text;
  //set layer text
  [self textLayer].string = text;
}

- (void)setTextColor:(UIColor *)textColor
{
  super.textColor = textColor;
  //set layer text color
  [self textLayer].foregroundColor = textColor.CGColor;
}

- (void)setFont:(UIFont *)font
{
  super.font = font;
  //set layer font
  CFStringRef fontName = (__bridge CFStringRef)font.fontName;
  CGFontRef fontRef = CGFontCreateWithFontName(fontName);
  [self textLayer].font = fontRef;
  [self textLayer].fontSize = font.pointSize;
  CGFontRelease(fontRef);
}
@end

3.3 CATransformLayer

  • CATransformLayer不同于普通的CALayer,因?yàn)樗荒茱@示它自己的內(nèi)容。只有當(dāng)存在了一個(gè)能作用域子圖層的變換它才真正存在。CATransformLayer并不平面化它的子圖層,所以它能夠用于構(gòu)造一個(gè)層級(jí)的3D結(jié)構(gòu)

3.4 CATiledLayer

  • CATiledLayer為載入大圖造成的性能問題提供了一個(gè)解決方案:將大圖分解成小片然后將他們單獨(dú)按需載入

3.5 CAGradientLayer

  • CAGradientLayer是用來生成兩種或更多顏色平滑漸變的。用Core Graphics復(fù)制一個(gè)CAGradientLayer并將內(nèi)容繪制到一個(gè)普通圖層的寄宿圖也是有可能的,但是CAGradientLayer的真正好處在于繪制使用了硬件加速。

3.6 CAReplicatorLayer:(反射效果)

  • CAReplicatorLayer的目的是為了高效生成許多相似的圖層。它會(huì)繪制一個(gè)或多個(gè)圖層的子圖層,并在每個(gè)復(fù)制體上應(yīng)用不同的變換。

3.7 CAEmitterLayer(粒子、火焰特效)

  • 簡(jiǎn)介CAEmitterLayer是一個(gè)高性能的粒子引擎,被用來創(chuàng)建實(shí)時(shí)例子動(dòng)畫如:煙霧,火,雨等等這些效果。
  • CAEmitterCell
    CAEmitterLayer看上去像是許多CAEmitterCell的容器,這些CAEmitierCell定義了一個(gè)例子效果。你將會(huì)為不同的例子效果定義一個(gè)或多個(gè)CAEmitterCell作為模版,同時(shí)CAEmitterLayer負(fù)責(zé)基于這些模版實(shí)例化一個(gè)粒子流。一個(gè)CAEmitterCell類似于一個(gè)CALayer:它有一個(gè)contents屬性可以定義為一個(gè)CGImage。

CAEMitterCell的屬性

  • 這種粒子的某一屬性的初始值。比如,color屬性指定了一個(gè)可以混合圖片內(nèi)容顏色的混合色。在示例中,我們將它設(shè)置為桔色。
  • 例子某一屬性的變化范圍。比如emissionRange屬性的值是2π,這意味著例子可以從360度任意位置反射出來。如果指定一個(gè)小一些的值,就可以創(chuàng)造出一個(gè)圓錐形。
  • 指定值在時(shí)間線上的變化。比如,在示例中,我們將alphaSpeed設(shè)置為-0.4,就是說例子的透明度每過一秒就是減少0.4,這樣就有發(fā)射出去之后逐漸消失的效果。
  • preservesDepth:是否將3D例子系統(tǒng)平面化到一個(gè)圖層(默認(rèn)值)或者可以在3D空間中混合其他的圖層。
  • renderMode:控制著在視覺上粒子圖片是如何混合的。你可能已經(jīng)注意到了示例中我們把它設(shè)置為kCAEmitterLayerAdditive,它實(shí)現(xiàn)了這樣一個(gè)效果:合并例子重疊部分的亮度使得看上去更亮。
#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIView *containerView;
@end

@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    CAEmitterLayer *emitter = [CAEmitterLayer layer];
    emitter.frame = self.containerView.bounds;
    [self.containerView.layer addSublayer:emitter];

    //configure emitter
     emitter.renderMode = kCAEmitterLayerAdditive;
    emitter.emitterPosition = CGPointMake(emitter.frame.size.width / 2.0, emitter.frame.size.height / 2.0);

    //create a particle template
    CAEmitterCell *cell = [[CAEmitterCell alloc] init];
    cell.contents = (__bridge id)[UIImage imageNamed:@"Spark.png"].CGImage;
    cell.birthRate = 150;
    cell.lifetime = 5.0;
    cell.color = [UIColor colorWithRed:1 green:0.5 blue:0.1 alpha:1.0].CGColor;
    cell.alphaSpeed = -0.4;
    cell.velocity = 50;
    cell.velocityRange = 50;
    cell.emissionRange = M_PI * 2.0;

    //add particle template to emitter
    emitter.emitterCells = @[cell];
}
@end

3.8 CAEAGLLayer

  • 用來顯示任意的OpenGL圖形,一般用不到。

3.9 AVPlayerLayer

  • AVPlayerLayer是CALayer的子類,它繼承了父類的所有特性,主要用于視頻播放。

4.0 CAScrollLayer

  • UIView中的UIScrollView的底層封裝。

四、視覺效果

4.1 圓角

  • conrnerRadius:控制著圖層角的曲率。(只影響背景顏色而不影響背景圖片或是子圖層),一般和masksToBounds配合著使用。
  • borderWidth:定義邊框粗細(xì)
  • borderColor:邊框的顏色

4.2 陰影

  • shadowOpacity:0.0(不可見)和1.0(完全不透明)之間的浮點(diǎn)數(shù);
  • shadowColor:控制陰影的顏色;
  • shadowOffset:控制陰影的方向和距離。默認(rèn)值是 {0, -3},意即陰影相對(duì)于Y軸有3個(gè)點(diǎn)的向上位移;
  • shadowRadius:控制著陰影的模糊度,當(dāng)值為0時(shí),陰影和視圖有非常確定的邊界線。值越大,邊界線看上去就會(huì)越來越模糊和自然;
  • shadowPath:一個(gè)CGPathRef類型(一個(gè)指向CGPath的指針)。我們可以通過這個(gè)屬性單獨(dú)于圖層形狀之外指定陰影的形狀;
  • mask:mask圖層比父圖層要小,只有在mask圖層里面的內(nèi)容才是它關(guān)心的,除此以外的一切都會(huì)被隱藏起來。代碼演示:
@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIImageView *imageView;
@end

@implementation ViewController

- (void)viewDidLoad
{
  [super viewDidLoad];

  //create mask layer
  CALayer *maskLayer = [CALayer layer];
  maskLayer.frame = self.layerView.bounds;
  UIImage *maskImage = [UIImage imageNamed:@"Cone.png"];
  maskLayer.contents = (__bridge id)maskImage.CGImage;

  //apply mask to image layer
  self.imageView.layer.mask = maskLayer;
}
@end

效果:


mask

4.3拉伸過濾:

view.layer.magnificationFilter = kCAFilterNearest;

4.4 組透明

  • 透明度會(huì)疊加,即當(dāng)一個(gè)控件有子控件時(shí),設(shè)置父控件的透明度(UIView對(duì)應(yīng)alpha、CALayer對(duì)應(yīng)opacity),子控件的透明度也會(huì)被影響。設(shè)置CALayer的一個(gè)叫做shouldRasterize屬性來實(shí)現(xiàn)組透明的效果,如果它被設(shè)置為YES,在應(yīng)用透明度之前,圖層及其子圖層都會(huì)被整合成一個(gè)整體的圖片,這樣就沒有透明度混合的問題了:
    view.layer.shouldRasterize = YES;
    view.layer.rasterizationScale = [UIScreen mainScreen].scale;

五、變換

5.1 仿射變換CGAffineTransform(2D變換)

5.1.1 原理:
1. UIView的transform屬性是一個(gè)CGAffineTransform類型,用于在二維空間做旋轉(zhuǎn),縮放和平移;
2. CALayer對(duì)應(yīng)于UIView的transform屬性叫做affineTransform;
3. CALayer同樣也有一個(gè)transform屬性,但它的類型是CATransform3D。
5.1.2 主要方法:
CGAffineTransformMakeRotation(CGFloat angle);                    //旋轉(zhuǎn)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy);           //縮放
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty);  //平移

5.1.3 混合變換:CGAffineTransformIdentity

// 需求:先縮小50%,再旋轉(zhuǎn)30度,最后向右移動(dòng)200個(gè)像素
- (void)viewDidLoad
{
    [super viewDidLoad];
    //create a new transform
    CGAffineTransform transform = CGAffineTransformIdentity; 
    //scale by 50%
    transform = CGAffineTransformScale(transform, 0.5, 0.5);
    //rotate by 30 degrees
    transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0);
    //translate by 200 points
    transform = CGAffineTransformTranslate(transform, 200, 0);
    //apply transform to layer
    self.layerView.layer.affineTransform = transform;
}

3D變換CATransform3D

5.2.1 主要方法:
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z);  //旋轉(zhuǎn)
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz);  //縮放
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz);  //平移

5.2.2 透視投影:m34

m34的默認(rèn)值是0,我們可以通過設(shè)置m34為-1.0 / d來應(yīng)用透視效果,d代表了想象中視角相機(jī)和屏幕之間的距離,通常500-1000就已經(jīng)很好了。

5.2.3 滅點(diǎn)

當(dāng)在透視角度繪圖的時(shí)候,遠(yuǎn)離相機(jī)視角的物體將會(huì)變小變遠(yuǎn),當(dāng)遠(yuǎn)離到一個(gè)極限距離,它們可能就縮成了一個(gè)點(diǎn),于是所有的物體最后都匯聚消失在同一個(gè)點(diǎn)(在現(xiàn)實(shí)中,這個(gè)點(diǎn)通常是視圖的中心)

  • sublayerTransform:它也是CATransform3D類型,它會(huì)影響到所有的子圖層。這意味著你可以一次性對(duì)包含這些圖層的容器做變換,于是所有的子圖層都自動(dòng)繼承了這個(gè)變換方法:
@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic, weak) IBOutlet UIView *layerView1;
@property (nonatomic, weak) IBOutlet UIView *layerView2;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //apply perspective transform to container
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = - 1.0 / 500.0;
    self.containerView.layer.sublayerTransform = perspective;
    //rotate layerView1 by 45 degrees along the Y axis
    CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
    self.layerView1.layer.transform = transform1;
    //rotate layerView2 by 45 degrees along the Y axis
    CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);
    self.layerView2.layer.transform = transform2;
}

六、隱式動(dòng)畫

事務(wù)(CATransaction)

  • 事務(wù)實(shí)際上是Core Animation用來包含一系列屬性動(dòng)畫集合的機(jī)制,任何用指定事務(wù)去改變可以做動(dòng)畫的圖層屬性都不會(huì)立刻發(fā)生變化,而是當(dāng)事務(wù)一旦提交的時(shí)候開始用一個(gè)動(dòng)畫過渡到新值

主要用法:

  [CATransaction begin]; // 入棧
  [CATransaction commit]; //出棧
  +setAnimationDuration: //設(shè)置當(dāng)前事務(wù)的動(dòng)畫時(shí)間
  +animationDuration // 獲取值(默認(rèn)0.25秒)
  [CATransaction setDisableActions:YES]; //對(duì)所有屬性關(guān)閉隱式動(dòng)畫

隱式動(dòng)畫如何實(shí)現(xiàn):

  • 圖層首先檢測(cè)它是否有委托,并且是否實(shí)現(xiàn)CALayerDelegate協(xié)議指定的-actionForLayer:forKey方法。如果有,直接調(diào)用并返回結(jié)果。
  • 如果沒有委托,或者委托沒有實(shí)現(xiàn)-actionForLayer:forKey方法,圖層接著檢查包含屬性名稱對(duì)應(yīng)行為映射的actions字典。
  • 如果actions字典沒有包含對(duì)應(yīng)的屬性,那么圖層接著在它的style字典接著搜索屬性名。
  • 最后,如果在style里面也找不到對(duì)應(yīng)的行為,那么圖層將會(huì)直接調(diào)用定義了每個(gè)屬性的標(biāo)準(zhǔn)行為的-defaultActionForKey:方法。

所以一輪完整的搜索結(jié)束之后,-actionForKey:要么返回空(這種情況下將不會(huì)有動(dòng)畫發(fā)生),要么是CAAction協(xié)議對(duì)應(yīng)的對(duì)象,最后CALayer拿這個(gè)結(jié)果去對(duì)先前和當(dāng)前的值做動(dòng)畫。

七、顯式動(dòng)畫

7.1 關(guān)鍵幀動(dòng)畫(CAKeyframeAnimation)

和CABasicAnimation類似,CAKeyframeAnimation同樣是CAPropertyAnimation的一個(gè)子類,它依然作用于單一的一個(gè)屬性,但是和CABasicAnimation不一樣的是,它不限制于設(shè)置一個(gè)起始和結(jié)束的值,而是可以根據(jù)一連串隨意的值來做動(dòng)畫。

  • 關(guān)鍵幀起源于傳動(dòng)動(dòng)畫,意思是指主導(dǎo)的動(dòng)畫在顯著改變發(fā)生時(shí)重繪當(dāng)前幀(也就是關(guān)鍵幀),每幀之間剩下的繪制(可以通過關(guān)鍵幀推算出)將由熟練的藝術(shù)家來完成。CAKeyframeAnimation也是同樣的道理:你提供了顯著的幀,然后Core Animation在每幀之間進(jìn)行插入。
代碼:
- (void)viewDidLoad
{
    [super viewDidLoad];
    //create a path
    ...
    //create the keyframe animation
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    // 平移動(dòng)畫
    animation.keyPath = @"position";
    //持續(xù)時(shí)間
    animation.duration = 4.0;
    // 動(dòng)畫路徑
    animation.path = bezierPath.CGPath;
    // *圖層將會(huì)根據(jù)曲線的切線自動(dòng)旋轉(zhuǎn)*
    animation.rotationMode = kCAAnimationRotateAuto;
    [shipLayer addAnimation:animation forKey:nil];
}

八、動(dòng)畫組CAAnimationGroup

  • CAAnimationGroup是另一個(gè)繼承于CAAnimation的子類,它添加了一個(gè)animations數(shù)組的屬性,用來組合別的動(dòng)畫。實(shí)例代碼:
- (void)viewDidLoad
{
    [super viewDidLoad];
    //create a path
    UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
    [bezierPath moveToPoint:CGPointMake(0, 150)];
    [bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
    //draw the path using a CAShapeLayer
    CAShapeLayer *pathLayer = [CAShapeLayer layer];
    pathLayer.path = bezierPath.CGPath;
    pathLayer.fillColor = [UIColor clearColor].CGColor;
    pathLayer.strokeColor = [UIColor redColor].CGColor;
    pathLayer.lineWidth = 3.0f;
    [self.containerView.layer addSublayer:pathLayer];
    //add a colored layer
    CALayer *colorLayer = [CALayer layer];
    colorLayer.frame = CGRectMake(0, 0, 64, 64);
    colorLayer.position = CGPointMake(0, 150);
    colorLayer.backgroundColor = [UIColor greenColor].CGColor;
    [self.containerView.layer addSublayer:colorLayer];
//create the position animation
    CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];
    animation1.keyPath = @"position";
    animation1.path = bezierPath.CGPath;
    animation1.rotationMode = kCAAnimationRotateAuto;
    //create the color animation
    CABasicAnimation *animation2 = [CABasicAnimation animation];
    animation2.keyPath = @"backgroundColor";
    animation2.toValue = (__bridge id)[UIColor redColor].CGColor;
    //create group animation
    CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
    groupAnimation.animations = @[animation1, animation2]; 
    groupAnimation.duration = 4.0;
    //add the animation to the color layer
    [colorLayer addAnimation:groupAnimation forKey:nil];
}

九、CATransition(過渡動(dòng)畫)

  • type(動(dòng)畫類型)

    • kCATransitionFade (淡入淡出)
    • kCATransitionMoveIn(從頂部滑動(dòng)進(jìn)入)
    • kCATransitionPush
    • kCATransitionReveal
  • subtype(動(dòng)畫方向)

    • kCATransitionFromRight
    • kCATransitionFromLeft
    • kCATransitionFromTop
    • kCATransitionFromBottom
  • 在動(dòng)畫過程中取消動(dòng)畫

- (void)removeAnimationForKey:(NSString *)key; // 移除某個(gè)動(dòng)畫
- (void)removeAllAnimations; // 移除所有動(dòng)畫

十、CAMediaTiming協(xié)議

10.1 概念

  • CAMediaTiming協(xié)議定義了在一段動(dòng)畫內(nèi)用來控制逝去時(shí)間的屬性的集合,CALayer和CAAnimation都實(shí)現(xiàn)了這個(gè)協(xié)議,所以時(shí)間可以被任意基于一個(gè)圖層或者一段動(dòng)畫的類控制。

10.2 屬性

  • duration:CFTimeInterval的類型,對(duì)將要進(jìn)行的動(dòng)畫的一次迭代指定了時(shí)間;
  • repeatCount:動(dòng)畫重復(fù)的迭代次數(shù);
  • repeatDuration:動(dòng)畫重復(fù)一個(gè)指定的時(shí)間,而不是指定次數(shù);
  • autoreverses:(BOOL類型)在每次間隔交替循環(huán)過程中自動(dòng)回放。

10.3 注意

  • duration和repeatCount默認(rèn)都是0。但這不意味著動(dòng)畫時(shí)長(zhǎng)為0秒,或者0次,這里的0僅僅代表了“默認(rèn)”,也就是0.25秒和1次;
  • 把repeatDuration設(shè)置為INFINITY,于是動(dòng)畫無限循環(huán)播放,設(shè)置repeatCount為INFINITY也有同樣的效果。
  • repeatCount和repeatDuration可能會(huì)相互沖突,所以你只要對(duì)其中一個(gè)指定非零值.

10.4 相對(duì)時(shí)間

  • beginTime:指定了動(dòng)畫開始之前的的延遲時(shí)間。這里的延遲從動(dòng)畫添加到可見圖層的那一刻開始測(cè)量,默認(rèn)是0(就是說動(dòng)畫會(huì)立刻執(zhí)行)
  • speed:是一個(gè)時(shí)間的倍數(shù),默認(rèn)1.0,減少它會(huì)減慢圖層/動(dòng)畫的時(shí)間,增加它會(huì)加快速度。如果2.0的速度,那么對(duì)于一個(gè)duration為1的動(dòng)畫,實(shí)際上在0.5秒的時(shí)候就已經(jīng)完成了.
  • timeOffset:增加timeOffset只是讓動(dòng)畫快進(jìn)到某一點(diǎn),例如,對(duì)于一個(gè)持續(xù)1秒的動(dòng)畫來說,設(shè)置timeOffset為0.5意味著動(dòng)畫將從一半的地方開始.

基于定時(shí)器的動(dòng)畫

NSTimer并不準(zhǔn)確的原因:

iOS上的每個(gè)線程都管理了一個(gè)NSRunloop,通過一個(gè)循環(huán)來完成一些任務(wù)列表。當(dāng)你設(shè)置一個(gè)NSTimer,他會(huì)被插入到當(dāng)前任務(wù)列表中,然后直到指定時(shí)間過去之后才會(huì)被執(zhí)行。但是何時(shí)啟動(dòng)定時(shí)器并沒有一個(gè)時(shí)間上限,而且它只會(huì)在列表中上一個(gè)任務(wù)完成之后開始執(zhí)行。這通常會(huì)導(dǎo)致有幾毫秒的延遲,但是如果上一個(gè)任務(wù)過了很久才完成就會(huì)導(dǎo)致延遲很長(zhǎng)一段時(shí)間.

性能優(yōu)化(待完善)

cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 書寫的很好,翻譯的也棒!感謝譯者,感謝感謝! iOS-Core-Animation-Advanced-Techni...
    錢噓噓閱讀 2,429評(píng)論 0 6
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,688評(píng)論 6 30
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫全貌。在這里你可以看...
    F麥子閱讀 5,267評(píng)論 5 13
  • 顯式動(dòng)畫 顯式動(dòng)畫,它能夠?qū)σ恍傩宰鲋付ǖ淖远x動(dòng)畫,或者創(chuàng)建非線性動(dòng)畫,比如沿著任意一條曲線移動(dòng)。 屬性動(dòng)畫 ...
    清風(fēng)沐沐閱讀 2,093評(píng)論 1 5
  • G156一班7組李然的周總結(jié)分享 1. 本周我的目標(biāo)是什么? 完成當(dāng)天的讀書進(jìn)度和英語打卡,親子班打卡,PPT練習(xí)...
    然_951c閱讀 158評(píng)論 0 0

友情鏈接更多精彩內(nèi)容