動畫

1.視圖動畫

UIView提供了豐富的動畫功能,最常見是animateWithDuration:animations: completion:了欺旧,我們先看下面這個簡單的例子:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.circleView = [[CircleView alloc] initWithFrame:
                       CGRectMake(0, 0, 20, 20)];
    self.circleView.center = CGPointMake(100, 40);
    [[self view] addSubview:self.circleView];
    
    self.squareView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
    _squareView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:_squareView];
    
    UITapGestureRecognizer *g = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dropAnimate:)];
    [[self view] addGestureRecognizer:g];
}

- (void)dropAnimate:(UIGestureRecognizer *)recognizer {
    [UIView animateWithDuration:3 animations:^{
         recognizer.enabled = NO;
         self.circleView.center = CGPointMake(100, 300);
        
        CGRect newFrame = CGRectMake(self.squareView.frame.origin.x + 150,
                                     self.squareView.frame.origin.y,
                                     self.squareView.frame.size.width,
                                     self.squareView.frame.size.height);
        self.squareView.frame = newFrame;
        self.squareView.alpha = 0.5;       
     }
     completion:^(BOOL finished){
         [UIView animateWithDuration:1 animations:^{
              self.circleView.center = CGPointMake(250, 300);
          }
          completion:^(BOOL finished){
              recognizer.enabled = YES;
          }
          ];
     }];
}

這是一種基于視圖的最簡單的動畫了栅哀,常用于大小称龙、位置、不透明度的變換痴柔,運行結(jié)果如下:

上面的例子中马昨,我們只要在animations中寫入我們需要進行動畫效果的view的結(jié)束狀態(tài),然后在animateWithDuration中給出動畫時間,改方法就會自動完成動畫效果疙渣。

此外,我們還使用了recognizer.enabled = NO來禁止動畫過程中的手勢觸摸泼菌,防止動畫過程中你再次觸摸后又會重新開始動畫效果。

為了讓動畫看起來更酷哗伯,你需要使用Core Animation.Core Animation中最基礎也是最重要的部分就是CALayer焊刹。

2.CALayer

在iOS中,你能看得見摸得著的東西基本上都是UIView俩滥,比如一個按鈕贺奠、一個文本標簽、一個文本輸入框挂据、一個圖標等等儿普,這些都是UIView。UIView之所以能顯示在屏幕上婚脱,完全是因為它內(nèi)部的一個圖層勺像,即CALayer。

換句話說篮洁,UIView本身不具備顯示的功能,擁有顯示功能的是它內(nèi)部的圖層袁波。,CALayer和UIView很多方面都很像蜗侈,它也有位置、大小枷颊、變形和內(nèi)容,和UIView不同在于它不能處理事件(如觸摸事件)信卡,它完全屬于繪制那方面的內(nèi)容题造。所以UIView使用CALayer來管理繪制內(nèi)容,這樣兩者就可以協(xié)調(diào)得很好丢习。

使用之前首先記得引用:#import <QuartzCore/QuartzCore.h>.

CALayer 能夠?qū)?UIView 做許多設定仔蝌,如:陰影、邊框渊鞋、圓角和透明效果等瞧挤,且這些設定都是很有用的

1.borderWidth 和 boarderColor : 邊框顏色和寬度;
2contents:顯示的圖片內(nèi)容:CDImage
3.cornerRadius : UIView 的圓角执俩;
4masksToBounds :設為true切去超過邊界的子視圖,和UIView的clipsToBounds類似癌刽;
4shadowColor: 設置shadow的顏色
5.shadowPath : 設置shadow的位置
6.shadowOffset :設置陰影的偏移量,如果為正數(shù)衡奥,則代表為往右邊偏移
7.shadowOpacity :設置陰影的透明度(0~1之間远荠,0表示完全透明)
8.shadowRadius : shadow的漸變距離,從外圍開始档址,往里漸變shadowRadius距離
9.bounds : UIView 的大辛诎稹;
10.opacity : UIView 的透明效果含友;

a.設置view的layer屬性

我們在storyBoard中拖入一個120*120的UIView并連接至IBOutler:

設置UIView 的邊框顏色和寬度和圓角校辩,注意,設置UIView的圓角,若為UIView是正方形宜咒,cornerRadius是邊長的一半的話,則顯示為圓形儿咱。

    self.CALayoutView.layer.borderWidth=5;
    self.CALayoutView.layer.borderColor=[UIColor purpleColor].CGColor;
    self.CALayoutView.layer.cornerRadius=60;

如下:

在view的圖層上添加一個image并設置陰影效果:

    self.CALayoutView.layer.contents=(id)[UIImage imageNamed:@"photo"].CGImage;
    self.CALayoutView.layer.shadowColor=[UIColor blackColor].CGColor;
    self.CALayoutView.layer.shadowOffset=CGSizeMake(15, 5);
    self.CALayoutView.layer.shadowOpacity=0.6;
    self.CALayoutView.layer.shadowRadius = 1;

裁剪視圖:

self.CALayoutView.layer.masksToBounds = YES;

不過這樣陰影效果也裁去了:

b.子類化CALayer

你可以通過子類化CALayer并覆蓋以下方法:

[CALayer display]
[CALayer drawInContext:]

覆蓋圖層的display方法可直接設置圖層的contents屬性混埠。

覆蓋圖層的drawInContext:方法可以將需要的內(nèi)容繪制到提供的圖形上下文中钳宪。

選擇何種方法依賴于在繪圖過程中你需要多少的控制扳炬。display方法是更新圖層內(nèi)容的主要入口點,所以覆蓋這個方法讓你處于完全的過程控制中半醉。覆蓋display方法也意味你需要負責contents屬性創(chuàng)建CGImageRef對象劝术。如果你只是想繪制內(nèi)容(或讓你的圖層管理繪圖操作),你可以覆蓋drawInContext:方法并讓圖層為你創(chuàng)建內(nèi)容儲備衬吆。
如下:

MyLayer.m

@implementation MyLayer

-(void)display{
    self.bounds=CGRectMake(50, 50, 50, 50);
    self.position=CGPointMake(50, 50);
    self.contents=(id)[UIImage imageNamed:@"photo"].CGImage;
    self.cornerRadius=5;
    self.masksToBounds=YES;
    self.borderWidth=3;
    self.borderColor=[UIColor brownColor].CGColor;
}

然后在view的layer圖層添加subLayer

    CALayer *myLayer = [MyLayer layer];
    [myLayer setNeedsDisplay];
    [self.view.layer addSublayer:myLayer];

效果:

c.使用代理提供圖層的內(nèi)容

或者使用代理對象(即UIView或ViewController作為代理對象)實現(xiàn)以下方法

[delegate displayLayer:]
[delegate drawLayer:inContext:]

如果你的代理實現(xiàn)了displayLayer:方法咆槽,實現(xiàn)方法負責創(chuàng)建位圖并賦值給contents屬性圈纺。一般實現(xiàn)該方法是因為位圖有多種狀態(tài)并且都有各自的狀態(tài),按鈕就是這樣子的灯谣。

如果你沒有預渲染的圖片或者輔助對象來創(chuàng)建位圖蛔琅。代理對象可以使用drawLayer:inContext:方法,Core Animation創(chuàng)建一個位圖辜窑,創(chuàng)建一個用于繪制位圖的上下文,并調(diào)用代理方法填充該位圖穆碎。你的代理方法所要做的是將內(nèi)容畫在圖形上下文上。一般可以使用Core Graphics來繪制方面,不過使用UIGraphicsPushContext方法的話色徘,也可以通過UIKit做到。

代理對象必須實現(xiàn)displayLayer:或者drawLayer:inContext方法之一横腿。如果代理對象把這兩個方法都實現(xiàn)了辙培,圖層只調(diào)用displayLayer:方法。

不過有一個需要注意的問題搀别,在自定義view中(子類化CALayer也是)上述方法不會自己調(diào)用尾抑,只能自己通過setNeedDisplay方法標記CALayer需要重繪,這樣就可以自動繪制所有子視圖了榜苫。UIView默認在你需要它的時候繪制翎冲,而CALayer則在你明確要求它時才會繪制。

[self.layer setNeedsDisplay];

我們來舉一個例子驹饺,在drawLayer:inContext中通過UIKit進行繪制缴渊。(使用Core Graphics的方法可以見上一篇文章)

DelegateView.m

- (id)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self) {
    [self.layer setNeedsDisplay];
  }
  return self;
}

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
  UIGraphicsPushContext(ctx);
  [[UIColor lightGrayColor] set];
  UIRectFill(layer.bounds);

  UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
  UIColor *color = [UIColor blackColor];

  NSMutableParagraphStyle *style = [NSMutableParagraphStyle new];
  [style setAlignment:NSTextAlignmentCenter];
  
  NSDictionary *attribs = @{NSFontAttributeName: font,
                            NSForegroundColorAttributeName: color,
                            NSParagraphStyleAttributeName: style};

  NSAttributedString *
  text = [[NSAttributedString alloc] initWithString:@"孫悟空"
                                         attributes:attribs];

  [text drawInRect:CGRectInset([layer bounds], 10, 10)];
  UIGraphicsPopContext();
}

CALayoutViewController.m

    UIView *delegateView = [[DelegateView alloc] initWithFrame:CGRectMake(120, 400, 120, 50)];
    delegateView.center = self.view.center;
    [self.view addSubview:delegateView];

注意上面衔沼,我們不需要把UIView設置為CALayer的delegate昔瞧,因為UIView對象已經(jīng)是它內(nèi)部根層的delegate自晰,再次設置為其他層的delegate就會出問題擎鸠。如果你是在控制器中實現(xiàn)CALayer的delegate方法缘圈,你就需要指定:

layer.delegate=self

效果:

當UIView需要在屏幕顯示時糟把,它內(nèi)部會準備好一個CGContextRef(圖形上下文),然后調(diào)用delegate的drawLayer:inContext:方法遣疯,并且傳入已經(jīng)準備好的CGContextRef對象。

而UIView在drawLayer:inContext:方法中又會調(diào)用自己的drawRect:方法数苫。平時在drawRect:中通過UIGraphicsGetCurrentContext()獲取的就是以上傳入的CGContextRef對象辨液,在drawRect:中完成的所有繪圖都會填入層的CGContextRef中,然后被拷貝至屏幕止吁。

3.開始動畫

先看一張類的繼承結(jié)構(gòu)圖:

CAAnimation是所有動畫類的父類敬惦,但是它不能直接使用,應該使用它的子類俄删。能用的動畫類只有4個子類:CABasicAnimation奏路、CAKeyframeAnimation、CATransition迅矛、CAAnimationGroup潜叛。CAMediaTiming是一個協(xié)議(protocol)壶硅。

CAPropertyAnimation是CAAnimation的子類庐椒,但是不能直接使用蚂踊,要想創(chuàng)建動畫對象,應該使用它的兩個子類:CABasicAnimation和CAKeyframeAnimation棱诱。

它有個NSString類型的keyPath屬性涝动,你可以指定CALayer的某個屬性名為keyPath,并且對CALayer的這個屬性的值進行修改靡菇,達到相應的動畫效果厦凤。比如育苟,指定@"position"為keyPath,就會修改CALayer的position屬性的值笨腥,以達到平移的動畫效果

1).隱式動畫

上一篇文章我們講了如何在圖層中繪圖勇垛,現(xiàn)在需要開始使用圖層來創(chuàng)建動畫了。如下所示谆级,我們對MyLayer添加以兩秒到達終點的移動效果讼积。

- (void)viewDidLoad {
...省略
[self.view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(drop:)]];
}

- (void)drop:(UIGestureRecognizer *)recognizer {
    [CATransaction setAnimationDuration:1.0];
    NSArray *layers = self.view.layer.sublayers;
    NSLog(@"--%@",layers);
    //由打印出來的數(shù)組得知第5個是MyLayer
    CALayer *layer = [layers objectAtIndex:4];
    CGPoint toPoint = CGPointMake(160, 210);
    [layer setContents:(id)[UIImage imageNamed:@"id"].CGImage];
    [layer setPosition:toPoint];
    [layer setBounds:CGRectMake(0, 0, 90, 90)];
}

每一個UIView內(nèi)部都默認關聯(lián)著一個CALayer勤众,我們可用稱這個Layer為Root Layer(根層),所有的非Root Layer们颜,也就是手動創(chuàng)建的CALayer對象(比如上面例子中的MyLayer)吕朵,都存在著隱式動畫猎醇。

什么是隱式動畫?
當對非Root Layer的部分屬性進行修改時努溃,默認會自動產(chǎn)生一些動畫效果,這些屬性稱為Animatable Properties(可動畫屬性)

幾乎所有的層的屬性都是隱性可動畫的硫嘶,你可以查找文檔中那些屬性是可動畫屬性:

例如上面那個例子的運行效果如下:

2).顯式動畫

隱式動畫大部分情況下可以達到你的要求,不過有時候你需要更多的控制梧税,這就需要用到CAAnimation了沦疾。隱式動畫就是通過CAAnimation來實現(xiàn)的哮塞,因此所有可以在隱式動畫完成的事情在顯式動畫中都可以做到彻桃。

下面是最基本的動畫CABasicAnimation的例子:

    CABasicAnimation *anim = [CABasicAnimation  animationWithKeyPath:@"opacity"];
    anim.fromValue = @1.0;
    anim.toValue = @0.0;
    anim.autoreverses = YES;
    anim.repeatCount = INFINITY;
    anim.duration = 2.0;
    [layer addAnimation:anim forKey:@"anim"];

效果如下:它會每隔兩秒重復繪制一次圖層,將不透明度從1改為0剔交。

你可以通過以下方法移除這個動畫來停止它:

[layer removeAnimationForKey:@"anim"];

動畫有它的(key)關鍵幀岖常、(fromValue)起始值葫督、(toValue)目標值橄镜、(timingFunction)時間函數(shù)洽胶、(duration)持續(xù)時間等。它的工作原理是創(chuàng)建圖層的多個副本丐怯,然后把它們顯示出來读跷。我們再看另外一個動畫:

    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"position.x";
    animation.byValue = @120;
    animation.duration = 2;
    animation.beginTime = CACurrentMediaTime()+1.5;
    [layer addAnimation:animation forKey:@"positionX"];

注意動畫的鍵路徑效览,也就是 position.x,實際上包含一個存儲在 position 屬性中的 CGPoint 結(jié)構(gòu)體成員订雾。這是 Core Animation 一個非常方便的特性嘿期。另外我們可以用byValue替代fromValue和toValue,只需要指定它的變化值伯顶,不需要指定它的起始值和目標值秀睛。

關于beginTime下一小節(jié)會講到抽兆。

效果如下:

有一個問題辫红,那就是動畫結(jié)束后圖層會很快地回到原點贴妻,我們把這種現(xiàn)象叫作jump back(閃回),要解決這個問題你需要了解model layer(模型層)和presentation layer(表示層)的概念和區(qū)別澎胡。

模型層是由開始動畫前的CALayer對象的屬性定義的攻谁。當開始動畫后戚宦,CAAnimation創(chuàng)建了CALayer對象的副本并進行修改阁苞,使其變成表現(xiàn)層祠挫,你可以大致理解為就是它們在屏幕上顯示什么內(nèi)容等舔。

前面的示例中,當執(zhí)行動畫時甚牲,狀態(tài)從模型層變?yōu)楸憩F(xiàn)層丈钙,表現(xiàn)層被繪制到屏幕上,繪制完成后劫笙,所有的更改都會丟失并由模型層決定當前狀態(tài)填大,因為模型層沒有改變俏橘,所以會恢復到一開始的狀態(tài)寥掐。

解決方法1:你可以通過設置動畫的 fillMode 屬性為 kCAFillModeForwards或kCAFillModeBoth使得動畫 以留在最終狀態(tài)曹仗,并設置removedOnCompletion 為 NO 以防止它被自動移除:

animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;

但這不是好的解決方法怎茫,因為這樣模型層永遠不會更新轨蛤,如果之后對它進行隱性動畫祥山,那它不會正常工作缝呕。

解決方法2:直接在 model layer 上更新屬性

我們先移除上面的隱式動畫(待會會講到為什么)供常,然后

    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"position.x";
    animation.fromValue = @50;
    animation.toValue = @170;
    //animation.byValue = @120;
    
    animation.duration = 2;
    animation.beginTime = CACurrentMediaTime()+1.2;
    [layer addAnimation:animation forKey:@"positionX"];
    
    layer.position = CGPointMake(170, 50);

注意這種情況下栈暇,我們必須指定fromValue和toValue源祈,不能使用byValue,我們最后指定了模型層的layer.position = CGPointMake(170, 50)手销,看看效果怎樣

啊哦锋拖,你發(fā)現(xiàn)了沒姑隅,現(xiàn)在是開始前有一個閃回(摔桌>笞病)

不過我們可以加入下面這句痪蝇,使得它在動畫開始之前不做任何動作

animation.fillMode = kCAFillModeBackwards;

關于kCAFillModeBackward和kCAFillModeForward的概念可以看下面這張圖:

再說一下之前被我們移除的隱性動畫趁矾,其實我們真正需要移除的是下面這個

[layer setPosition:toPoint];

因為它和我們的顯性動畫有沖突给僵。所以最好的解決辦法是在執(zhí)行顯示動畫時關閉隱式動畫

    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    ...省略
    [CATransaction commit];

所以其實我們可以針對這種情況寫一個分類:

@implementation CALayer (CALayer_RNAnimation)

- (void)setValue:(id)value
      forKeyPath:(NSString *)keyPath
        duration:(CFTimeInterval)duration
           delay:(CFTimeInterval)delay {
  [CATransaction begin];
  [CATransaction setDisableActions:YES];
  [self setValue:value forKeyPath:keyPath];
  CABasicAnimation *anim;
  anim = [CABasicAnimation animationWithKeyPath:keyPath];
  anim.duration = duration;
  anim.beginTime = CACurrentMediaTime() + delay;
  anim.fillMode = kCAFillModeBoth;
  anim.fromValue = [[self presentationLayer] valueForKey:keyPath];
  anim.toValue = value;
  [self addAnimation:anim forKey:keyPath];
  [CATransaction commit];
}

3).關于定時

Core Animation中的時間是相對的蔓同,一秒時間不一定就是一秒鐘斑粱,與坐標一樣脯爪,時間是可以縮放的痕慢。Core Animation遵守CAMediaTiming協(xié)議守屉,可以設置其speed屬性來縮放它的時間跨度。

你可能會需要在某個圖層的動畫結(jié)束后開始自己的動畫思灌,因此你需要對它們之間的時間進行轉(zhuǎn)換泰偿,就像轉(zhuǎn)換不同視圖中的點一樣耗跛。

   CAAnimation *otherAnim = [layer animationForKey:@"anim"];
   CFTimeInterval finish = otherAnim.beginTime + otherAnim.duration;
   myAnim.beginTime = [self convertTime:finish fromLayer:layer];

如果想引用當前時間调塌,可以使用CACurrentMediaTime()惠猿,例如:

    anim.beginTime = CACurrentMediaTime()+3.0;
    anim.fillMode = kCAFillModeBackwards;

該動畫會在前3秒保存不動偶妖,3秒后開始動畫趾访。

你想要為你的動畫定義超過兩個步驟扼鞋,我們可以使用更通用的 CAKeyframeAnimation云头,而不是去鏈接多個 CABasicAnimation 實例盘寡。

4).CAKeyframeAnimation

跟CABasicAnimation的區(qū)別是:CABasicAnimation只能從一個數(shù)值(fromValue)變到另一個數(shù)值(toValue)竿痰,而CAKeyframeAnimation會使用一個NSArray保存這些數(shù)值

包含以下屬性:

values:就是上述的NSArray對象影涉。里面的元素稱為”關鍵幀”(keyframe)蟹倾。動畫對象會在指定的時間(duration)內(nèi)肌厨,依次顯示values數(shù)組中的每一個關鍵幀

path:可以設置一個CGPathRef\CGMutablePathRef,讓層跟著路徑移動柑爸。path只對CALayer的anchorPoint和position起作用表鳍。如果你設置了path譬圣,那么values將被忽略

keyTimes:可以為對應的關鍵幀指定對應的時間點,其取值范圍為0到1.0,keyTimes中的每一個時間值都對應values中的每一幀.當keyTimes沒有設置的時候,各個關鍵幀的時間是平分的

CABasicAnimation可看做是最多只有2個關鍵幀的CAKeyframeAnimation

a).多步動畫

下面的例子我們值改變values的值厘熟,即定義關鍵幀盯漂。關鍵幀(keyframe)使我們能夠定義動畫中任意的一個點就缆,然后讓 Core Animation 填充所謂的中間幀竭宰。先看運行效果:

代碼如下:

- (IBAction)enter:(id)sender {
    if (![self.textField.text isEqualToString:@"123456"]) {
        [self lockAnimationForView:self.textField];
    }
}

-(void)lockAnimationForView:(UIView*)view
{
    CALayer *layer = [view layer];
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position.x";
    animation.values = @[ @0, @5, @10, @-10, @10, @5, @0 ];
    animation.keyTimes = @[ @0, @(1 / 6.0),@(2 / 6.0), @(3 / 6.0), @(5 / 6.0),@(2 / 6.0), @1 ];
    animation.duration = 0.4;
    
    animation.additive = YES;
    
    [layer addAnimation:animation forKey:@"shake"];
}

values 數(shù)組定義了UITextField應該到哪些位置切揭。設置 keyTimes 屬性讓我們能夠指定關鍵幀動畫發(fā)生的時間廓旬。它們被指定為關鍵幀動畫總持續(xù)時間的一個分數(shù)孕豹。

設置 additive 屬性為 YES 使 Core Animation 在更新表現(xiàn)層之前將動畫的值添加到模型層中去励背。這使我們能夠?qū)λ行问降男枰碌脑刂赜孟嗤膭赢嬕睹迹覠o需提前知道它們的位置。因為這個屬性從 CAPropertyAnimation 繼承莲趣,所以你也可以在使用 CABasicAnimation 時使用它妖爷。

b).沿路徑的動畫

CAKeyframeAnimation 提供了更加便利的 path 屬性使得view可以沿著復雜路徑的動畫運動絮识。

舉個例子次舌,我們?nèi)绾巫屢粋€ view 做圓周運動:

代碼如下:

-(void)pathAnimation:(UITapGestureRecognizer*)tap{
    tap.enabled = NO;
    CALayer *layer = [self.pathView layer];
    CGRect boundingRect = CGRectMake(-150, -150, 300, 300);
    
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position";
    animation.path = CFAutorelease(CGPathCreateWithEllipseInRect(boundingRect, NULL));
    animation.duration = 4;
    animation.additive = YES;
    animation.repeatCount = HUGE_VALF;
    animation.calculationMode = kCAAnimationPaced;
    animation.rotationMode = kCAAnimationRotateAuto;
    
    [layer addAnimation:animation forKey:@"path"];
}

我們使用 CGPathCreateWithEllipseInRect()創(chuàng)建一個圓形的 CGPath 作為我們的關鍵幀動畫的 path。

使用 calculationMode 是控制關鍵幀動畫時間的另一種方法逐沙。我們通過將其設置為 kCAAnimationPaced吩案,讓 Core Animation 向被驅(qū)動的對象施加一個恒定速度徘郭,不管路徑的各個線段有多長丧肴。將其設置為 kCAAnimationPaced 將無視所有我們已經(jīng)設置的 keyTimes芋浮。設置 rotationMode 屬性為 kCAAnimationRotateAuto 確保view沿著路徑旋轉(zhuǎn)纸巷。

5).時間函數(shù)

你會發(fā)現(xiàn)我們上面有些動畫有一些看起來不是很不自然何暇。那是因為我們在現(xiàn)實世界中看到的大部分運動需要時間來加速或減速裆站。為了給我們的動畫一個存在慣性的感覺羽嫡,我們可以通過引入一個 時間函數(shù) (timing function) (有時也被稱為 easing 函數(shù))來實現(xiàn)這個目標杭棵。該函數(shù)通過修改持續(xù)時間的分數(shù)來控制動畫的速度魂爪。

animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

還包含:kCAMediaTimingFunctionEaseIn, kCAMediaTimingFunctionEaseOut, kCAMediaTimingFunctionEaseInEaseOut滓侍,你們可以自己試試效果如何撩笆。

你還可以參見類似這種小型庫 RBBAnimation缸浦,它包含一個允許使用 更多復雜 easing 函數(shù) 的自定義子類 CAKeyframeAnimation裂逐,包括反彈和包含負分量的 cubic Bézier 函數(shù)絮姆。

6).動畫組

對于某些復雜的效果篙悯,可能需要同時為多個屬性進行動畫鸽照。CAAnimationGroup可以保存一組動畫對象,將CAAnimationGroup對象加入層后定血,組中所有動畫對象可以同時并發(fā)運行澜沟。

默認情況下茫虽,一組動畫對象是同時運行的濒析,也可以單獨通過設置動畫對象的beginTime屬性來更改動畫的開始時間,示例如下:

-(void)groupAnimation:(UITapGestureRecognizer*)tap{
    // 平移動畫
    CABasicAnimation *animation1 = [CABasicAnimation animation];
    animation1.keyPath = @"transform.translation.y";
    animation1.toValue = @(100);
    // 縮放動畫
    CABasicAnimation *animation2 = [CABasicAnimation animation];
    animation2.keyPath = @"transform.scale";
    animation2.toValue = @(0.0);
    // 旋轉(zhuǎn)動畫
    CABasicAnimation *animation3 = [CABasicAnimation animation];
    animation3.keyPath = @"transform.rotation";
    animation3.toValue = @(M_PI_2);

    // 組動畫
    CAAnimationGroup *groupAnima = [CAAnimationGroup animation];

    groupAnima.animations = @[animation1, animation2, animation3];

    //設置組動畫的時間
    groupAnima.duration = 2;
    groupAnima.fillMode = kCAFillModeForwards;
    groupAnima.removedOnCompletion = NO;
    [self.groupViewFirst.layer addAnimation:groupAnima forKey:@"group"];
}

運行效果:

你可以在這里下載完整的代碼。如果你覺得對你有幫助主经,希望你不吝嗇你的star:)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旨怠,一起剝皮案震驚了整個濱河市鉴腻,隨后出現(xiàn)的幾起案子爽哎,更是在濱河造成了極大的恐慌课锌,老刑警劉巖渺贤,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件志鞍,死亡現(xiàn)場離奇詭異固棚,居然都是意外死亡此洲,警方通過查閱死者的電腦和手機呜师,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門匣掸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事送爸∠В” “怎么了纹磺?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵橄杨,是天一觀的道長式矫。 經(jīng)常有香客問我采转,道長故慈,這世上最難降的妖魔是什么框全? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任克婶,我火速辦了婚禮情萤,結(jié)果婚禮上摹恨,老公的妹妹穿的比我還像新娘。我一直安慰自己睁宰,他們只是感情好,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布孝赫。 她就那樣靜靜地躺著青柄,像睡著了一般致开。 火紅的嫁衣襯著肌膚如雪双戳。 梳的紋絲不亂的頭發(fā)上飒货,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天膏斤,我揣著相機與錄音莫辨,去河邊找鬼沮榜。 笑死喻粹,一個胖子當著我的面吹牛守呜,可吹牛的內(nèi)容都是我干的查乒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了讥蟆?” 一聲冷哼從身側(cè)響起瘸彤,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤钧栖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啃奴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體最蕾,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡瘟则,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年醋拧,在試婚紗的時候發(fā)現(xiàn)自己被綠了丹壕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菌赖。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡琉用,死狀恐怖邑时,靈堂內(nèi)的尸體忽然破棺而出刁愿,到底是詐尸還是另有隱情到逊,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布件缸,位于F島的核電站他炊,受9級特大地震影響痊末,放射性物質(zhì)發(fā)生泄漏哩掺。R本人自食惡果不足惜嚼吞,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一舱禽、第九天 我趴在偏房一處隱蔽的房頂上張望誊稚。 院中可真熱鬧,春花似錦绽昏、人聲如沸全谤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毕骡。三九已至,卻和暖如春窿撬,著一層夾襖步出監(jiān)牢的瞬間劈伴,已是汗流浹背跛璧。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工追城, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留漓柑,地道東北人叨吮。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓茶鉴,卻偏偏與公主長得像涵叮,于是被迫代替她去往敵國和親割粮。 傳聞我的和親對象是個殘疾皇子舀瓢,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 概覽 在iOS中隨處都可以看到絢麗的動畫效果备图,實現(xiàn)這些動畫的過程并不復雜揽涮,今天將帶大家一窺iOS動畫全貌。在這里你...
    被吹落的風閱讀 1,563評論 1 2
  • 在iOS中隨處都可以看到絢麗的動畫效果幢痘,實現(xiàn)這些動畫的過程并不復雜颜说,今天將帶大家一窺ios動畫全貌门粪。在這里你可以看...
    每天刷兩次牙閱讀 8,495評論 6 30
  • 在iOS中隨處都可以看到絢麗的動畫效果玄妈,實現(xiàn)這些動畫的過程并不復雜拟蜻,今天將帶大家一窺iOS動畫全貌酝锅。在這里你可以看...
    F麥子閱讀 5,113評論 5 13
  • 在iOS實際開發(fā)中常用的動畫無非是以下四種:UIView動畫搔扁,核心動畫蟋字,幀動畫鹊奖,自定義轉(zhuǎn)場動畫。 1.UIView...
    請叫我周小帥閱讀 3,101評論 1 23
  • 概覽 在iOS中隨處都可以看到絢麗的動畫效果焰盗,實現(xiàn)這些動畫的過程并不復雜咒林,今天將帶大家一窺iOS動畫全貌。在這里你...
    Yiart閱讀 3,819評論 3 34