CAAnimation核心動畫

書籍是人類進步的階梯

總覽思維導圖

核心動畫思維導圖.png

一、圖層樹

1.1.contents

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

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

1.2 contentsScale

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

1.3 maskToBounds

  • UIView有一個叫做clipsToBounds的屬性可以用來決定是否顯示超出邊界的內容,CALayer對應的屬性叫做masksToBounds

1.4 contentsRect

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

1.5 contentsCenter

  • 其實是一個CGRect,它定義了一個固定的邊框和一個
    在圖層上可拉伸的區域。默認情況下,contentsCenter是{0, 0, 1, 1},這意
    味著如果大小(由conttensGravity決定)改變了,那么寄宿圖將會均勻地拉
    伸開。但是如果我們增加原點的值并減小尺寸。我們會在圖片的周圍創造
    一個邊框。圖2.9展示了contentsCenter設置為{0.25, 0.25, 0.5, 0.5}的效果。


    contentsCenter.png

1.6 -drawRect:方法:

  • 當視圖在屏幕上出現的時候 -drawRect:方法就會被自動調用;
  • 調用了-setNeedsDisplay方法時,-drawRect:方法會被調用;

二、圖層幾何學

2.1 frame、bounds、position

  • 當對圖層做變換的時候,比如旋轉或者縮放,frame實際上代表了覆蓋在圖層旋轉之后的整個軸對齊的矩形區域,也就是說frame的寬高可能和bounds的寬高不再一致了


    frame

2.2 錨點anchorPoint

  • anchorPoint是用來移動圖層的把柄。anchorPoint用單位坐標來描述,也就是圖層的相對坐標,圖層左上角是{0, 0},右下角是{1, 1},因此默認坐標是{0.5, 0.5}

2.3zPosition

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

2.4 -containsPoint

  • 接受一個在本圖層坐標系下的CGPoint,如果這個點在圖層frame范圍內就返回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

  • 方法接受一個CGPoint類型參數,而不是BOOL類型,它返回圖層本身,或者包含這個坐標點的葉子節點圖層:
- (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的優點:
    • 渲染快速。CAShapeLayer使用了硬件加速,繪制同一圖形會比用Core Graphics快很多;
    • 高效使用內存。一個CAShapeLayer不需要像普通CALayer一樣創建一個寄宿圖形,所以無論有多大,都不會占用太多的內存;
    • 不會被圖層邊界剪裁掉。一個CAShapeLayer可以在邊界之外繪制。
    • 不會出現像素化。當你給CAShapeLayer做3D變換時,它不像一個有寄宿圖的普通圖層一樣變得像素化。

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

  • 繪制圓角:( 需求:三個圓角,一個直角)
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其實是通過WebKit來實現繪制的,這樣就造成了當有很多文字的時候就會有極大的性能壓力。
  • CATextLayer使用了Core text,并且渲染得非常快。可以嘗試封裝一個CATextLayer用于替換UILabel

UILabel的替代品

  • 使用CATextLayer來封裝一個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,因為它不能顯示它自己的內容。只有當存在了一個能作用域子圖層的變換它才真正存在。CATransformLayer并不平面化它的子圖層,所以它能夠用于構造一個層級的3D結構

3.4 CATiledLayer

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

3.5 CAGradientLayer

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

3.6 CAReplicatorLayer:(反射效果)

  • CAReplicatorLayer的目的是為了高效生成許多相似的圖層。它會繪制一個或多個圖層的子圖層,并在每個復制體上應用不同的變換。

3.7 CAEmitterLayer(粒子、火焰特效)

  • 簡介CAEmitterLayer是一個高性能的粒子引擎,被用來創建實時例子動畫如:煙霧,火,雨等等這些效果。
  • CAEmitterCell
    CAEmitterLayer看上去像是許多CAEmitterCell的容器,這些CAEmitierCell定義了一個例子效果。你將會為不同的例子效果定義一個或多個CAEmitterCell作為模版,同時CAEmitterLayer負責基于這些模版實例化一個粒子流。一個CAEmitterCell類似于一個CALayer:它有一個contents屬性可以定義為一個CGImage。

CAEMitterCell的屬性

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

4.2 陰影

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

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

五、變換

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

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

5.1.3 混合變換:CGAffineTransformIdentity

// 需求:先縮小50%,再旋轉30度,最后向右移動200個像素
- (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);  //旋轉
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz);  //縮放
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz);  //平移

5.2.2 透視投影:m34

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

5.2.3 滅點

當在透視角度繪圖的時候,遠離相機視角的物體將會變小變遠,當遠離到一個極限距離,它們可能就縮成了一個點,于是所有的物體最后都匯聚消失在同一個點(在現實中,這個點通常是視圖的中心)

  • sublayerTransform:它也是CATransform3D類型,它會影響到所有的子圖層。這意味著你可以一次性對包含這些圖層的容器做變換,于是所有的子圖層都自動繼承了這個變換方法:
@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;
}

六、隱式動畫

事務(CATransaction)

  • 事務實際上是Core Animation用來包含一系列屬性動畫集合的機制,任何用指定事務去改變可以做動畫的圖層屬性都不會立刻發生變化,而是當事務一旦提交的時候開始用一個動畫過渡到新值

主要用法:

  [CATransaction begin]; // 入棧
  [CATransaction commit]; //出棧
  +setAnimationDuration: //設置當前事務的動畫時間
  +animationDuration // 獲取值(默認0.25秒)
  [CATransaction setDisableActions:YES]; //對所有屬性關閉隱式動畫

隱式動畫如何實現:

  • 圖層首先檢測它是否有委托,并且是否實現CALayerDelegate協議指定的-actionForLayer:forKey方法。如果有,直接調用并返回結果。
  • 如果沒有委托,或者委托沒有實現-actionForLayer:forKey方法,圖層接著檢查包含屬性名稱對應行為映射的actions字典。
  • 如果actions字典沒有包含對應的屬性,那么圖層接著在它的style字典接著搜索屬性名。
  • 最后,如果在style里面也找不到對應的行為,那么圖層將會直接調用定義了每個屬性的標準行為的-defaultActionForKey:方法。

所以一輪完整的搜索結束之后,-actionForKey:要么返回空(這種情況下將不會有動畫發生),要么是CAAction協議對應的對象,最后CALayer拿這個結果去對先前和當前的值做動畫。

七、顯式動畫

7.1 關鍵幀動畫(CAKeyframeAnimation)

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

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

八、動畫組CAAnimationGroup

  • CAAnimationGroup是另一個繼承于CAAnimation的子類,它添加了一個animations數組的屬性,用來組合別的動畫。實例代碼:
- (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(過渡動畫)

  • type(動畫類型)

    • kCATransitionFade (淡入淡出)
    • kCATransitionMoveIn(從頂部滑動進入)
    • kCATransitionPush
    • kCATransitionReveal
  • subtype(動畫方向)

    • kCATransitionFromRight
    • kCATransitionFromLeft
    • kCATransitionFromTop
    • kCATransitionFromBottom
  • 在動畫過程中取消動畫

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

十、CAMediaTiming協議

10.1 概念

  • CAMediaTiming協議定義了在一段動畫內用來控制逝去時間的屬性的集合,CALayer和CAAnimation都實現了這個協議,所以時間可以被任意基于一個圖層或者一段動畫的類控制。

10.2 屬性

  • duration:CFTimeInterval的類型,對將要進行的動畫的一次迭代指定了時間;
  • repeatCount:動畫重復的迭代次數;
  • repeatDuration:動畫重復一個指定的時間,而不是指定次數;
  • autoreverses:(BOOL類型)在每次間隔交替循環過程中自動回放。

10.3 注意

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

10.4 相對時間

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

基于定時器的動畫

NSTimer并不準確的原因:

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

性能優化(待完善)

cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 書寫的很好,翻譯的也棒!感謝譯者,感謝感謝! iOS-Core-Animation-Advanced-Techni...
    錢噓噓閱讀 2,327評論 0 6
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,573評論 6 30
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,147評論 5 13
  • 顯式動畫 顯式動畫,它能夠對一些屬性做指定的自定義動畫,或者創建非線性動畫,比如沿著任意一條曲線移動。 屬性動畫 ...
    清風沐沐閱讀 1,981評論 1 5
  • G156一班7組李然的周總結分享 1. 本周我的目標是什么? 完成當天的讀書進度和英語打卡,親子班打卡,PPT練習...
    然_951c閱讀 128評論 0 0