天天看點

【原】iOS學習44之動畫

1. 簡單動畫

 1> UIImageView GIF 動畫

  GIF圖的原理是:擷取圖檔,存儲在圖檔數組中,按照圖檔數組的順序将圖檔以一定的速度播放

  UIImageView *showGifimageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 100, 300, 300)];
    
    [self.view addSubview:showGifimageView];
    
    // 建立一個存儲圖檔的數組
    NSMutableArray *saveImageArray = [NSMutableArray array];
    
    // 擷取圖檔
    for (int i = 1; i < 12; i++) {
        // 拼接圖檔名
        NSString *imageName = [NSString stringWithFormat:@"%d.tiff", i];
        // 根據圖檔名擷取圖檔
        UIImage *image = [UIImage imageNamed:imageName];
        // 将圖檔加到數組
        [saveImageArray addObject:image];
    }
    // 設定gif的圖檔組
    showGifimageView.animationImages = saveImageArray;
    // 設定播放速率
    showGifimageView.animationDuration = 1;
    // 設定播放的次數
    showGifimageView.animationRepeatCount = 0;
    // 開始動畫
    [showGifimageView startAnimating];      

 2> UIActivityIndicatorView 風火輪動畫

  在APP中,加載界面的時候我們都會看到一個想風火輪的動畫在不停的轉,這個動畫其實是iOS中的一個類 UIActivityIndicatorView

// 加載旋轉的菊花效果
    // 無需設定frame
    UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    // 确定位置
    indicatorView.center = self.view.center;
    
    [self.view addSubview:indicatorView];
    
    // 将菊花動畫效果開啟
    [indicatorView startAnimating];      

 3> 動畫可以達到的效果

  • 傳達狀态
  • 提高使用者對直接操作的感覺
  • 幫助使用者可視化操作的結果

 4> 使用動畫應該注意

  • 謹慎添加動畫,尤其是在那些不能提供沉浸式使用者體驗(讓人專注在目前由設計者營造的情境下感到愉悅和滿足暫時忘記真實世界的情境)的App中。

  如果App主要關注一些嚴肅的任務或者生産性任務,那麼動畫就顯得多餘了,還會無端打亂App的使用流程,降低應用的性能,讓使用者從目前的任務中分心。

  • 開發者的自定義動畫應該适當符合内置iOS應用的動畫。

  使用者習慣于内置iOS App使用的精細動畫。事實上,使用者趨向于把視圖之間的平滑轉換,對裝置方向改變的流暢響應和基于實體力學的滾動效果看作是iOS體驗的一部分。除非你的應用能夠給使用者沉浸式的體驗—比如遊戲(自定義動畫應該可以與内置應用的動畫相媲美)

  • 使用風格類型一緻的動畫。

  在App中使用風格類型一緻的動畫非常重要,可以讓使用者建構基于使用App獲得的使用者體驗。

2. UIView動畫之UIView基礎動畫

 1> 概述

  • UIKit 直接将動畫內建到 UIView 類中,當内部的一些屬性發生改變時,UIView将為這些改變提供動畫支援。
  • 執行動畫的工作由 UIView 類自動完成,但仍希望在執行動畫時通知視圖,為此需要将改變屬性的代碼放在 [UIView beginAnimations:nil context:nil] 和 [UIView commitAnimations] 之間。

 2> UIView基礎動畫種類

  • UIView位置大小動畫(改變View的frame)
  • UIView顔色動畫(改變View的color)
  • UIView透明度動畫(改變View的alpha)
  • 仿射-翻轉rotation
  • 仿射-旋轉transform 

 3> UIView基礎動畫步驟

  • 第一步:開始UIView動畫
+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;      

  參數animationID: 是一個辨別符字元串,用于告訴系統要進行哪一個動畫,可以自由定義

  參數context:額外的上下文資訊傳遞,沒有就置為 nil

  • 第二步:設定動畫時長
+ (void)setAnimationDuration:(NSTimeInterval)duration;      

  參數duration:表示動畫持續的時間長度,系統預設為0.2s,具體值可以根據需求自行設定

  • 第三步:設定UIView動畫的回調代理
+ (void)setAnimationDelegate:(nullable id)delegate;       

  參數delegate:設定代理變量,一般為nil,代理主要用于監聽動畫的開始和結束

  • 第四步:處理相關的動畫

  主要是對frame、color、alpha、翻轉方向和旋轉角度的操作

  • 第五步:送出動畫效果
+ (void)commitAnimations;      

  該方法主要是送出動畫,也就是告訴系統動畫執行完成

 4> UIView位置大小動畫(改變View的frame)

// UIView動畫有開始beginAnimation,有結束commitAnimations
    // 第一步:開始UIView動畫
    [UIView beginAnimations:@"mov" context:nil];
    // 第二步:設定動畫時常
    [UIView setAnimationDuration:3];
    // 第三步:設定UIView動畫的回調代理
    [UIView setAnimationDelegate:self];
    // 第四步:設定相關的對象的frame
    _showView.frame = CGRectMake(100, 100, 200, 100);
    // 第五步:送出動畫效果
    [UIView commitAnimations];       

 5> UIView顔色動畫(改變View的color)

[UIView beginAnimations:@"color" context:nil];
    [UIView setAnimationDuration:4];
    [UIView setAnimationDelegate:self];
    _showView.backgroundColor = [UIColor purpleColor];
    [UIView commitAnimations];      

 6> UIView透明度動畫(改變View的alpha)

[UIView beginAnimations:@"alpha" context:nil];
    [UIView setAnimationDuration:5];
    [UIView setAnimationDelegate:self];
    _showView.alpha = 0.1;
    [UIView commitAnimations];      

 7> 仿射-翻轉rotation

// 第一步:開始UIView動畫
    [UIView beginAnimations:@"rotation" context:nil];
    // 第二步:設定動畫時常
    [UIView setAnimationDuration:0.5];
    // 第2.5步:設定淡入的效果(感覺效果不明顯)
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    // 第三步:設定UIView動畫的回調代理
    [UIView setAnimationDelegate:self];
    // 第4步:設定翻轉的方式
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:_showView cache:YES];
    [UIView commitAnimations];      

 8> 仿射-旋轉transform

[UIView beginAnimations:@"transform" context:nil];
    [UIView setAnimationDuration:2];
    [UIView setAnimationDelegate:self];
    // 第4步:設定旋轉角度
    CGAffineTransform transform = CGAffineTransformMakeRotation(-M_PI_2);
    // 第4.5步:設定旋轉角度的對象
    [_showView setTransform:transform];
    [UIView commitAnimations];      

 9> UIView基礎動畫回調方法

+ (void)setAnimationWillStartSelector:(nullable SEL)selector;
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;      

  這兩個方法預設是 nil,不能使用,一般使用它們的替代方法

- (void)animationWillStart:(NSString *)animationID context:(void *)context;
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;      

  實際操作的代碼

#pragma mark - UIViewAnimationDelegate的協定方法
- (void)animationWillStart:(NSString *)animationID context:(void *)context
{
    NSLog(@"%s__%d--ID = %@, context = %@", __FUNCTION__, __LINE__, animationID, context);
}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
    NSLog(@"%s__%d--ID = %@, context = %@", __FUNCTION__, __LINE__, animationID, context);
}      

  注:UIViewAnimationDelegate 代理不需要我們在遵循,系統已經封裝好了

3. UIView動畫之Block動畫

 1> Block簡單動畫

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;      
  • 參數duration:設定動畫時長
  • 參數animations:是一個Block,主要用于設定動畫
  • 參數completion:也是一個Block,主要用于設定在動畫結束後的一些操作
__weak typeof(self)weakSelf = self;
    // 第1個參數:設定動畫時長
    // 第2個參數:設定動畫
    // 第3個參數:動畫完成時進行的事情
    [UIView animateWithDuration:2 animations:^{
        weakSelf.playImageView.frame = CGRectMake(67, 74, 240, 286);
    } completion:^(BOOL finished) {
        NSLog(@"finished");
    }];      

 2> Block複雜動畫

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;      
  • 參數delay:動畫執行的延遲時間
  • 參數options:枚舉值動畫效果,有很多枚舉值,大家可以根據需要進行選取
// 第1個參數:設定動畫時長
    // 第2個參數:動畫的延遲時間
    // 第3個參數:枚舉值動畫效果
    // 第4個參數:設定動畫
    // 第5個參數:動畫完成時進行的事情
    __weak typeof(self)weakSelf = self;
    [UIView animateWithDuration:2 delay:1 options:UIViewAnimationOptionOverrideInheritedOptions animations:^{
        weakSelf.playImageView.center = weakSelf.view.center;
    } completion:^(BOOL finished) {
        NSLog(@"finished");
    }];      

 3> Block關鍵幀動畫

+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion       
  • 參數options:關鍵幀枚舉值動畫效果,有很多枚舉值,大家可以根據需要進行選取
  • 參數animations:是一個Block,主要用于設定動畫。在這裡需要添加一個方法,即建立Block的關鍵幀
    + (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations;      
  •   參數frameStartTime:幀動畫的開始時間
  •   參數frameDuration:幀動畫的持續時間
  •   參數animations:Block,用于設定動畫
// 第1個參數:設定動畫時長
    // 第2個參數:動畫的延遲時間
    // 第3個參數:關鍵幀枚舉值動畫效果
    // 第4個參數:開始動畫
    // 第5個參數:動畫完成時進行的事情
    __weak typeof(self)weakSelf = self;
    [UIView animateKeyframesWithDuration:2 delay:1 options:UIViewKeyframeAnimationOptionAllowUserInteraction animations:^{
        // 在這裡需要添加一個方法,即建立Block的關鍵幀
        // 幀動畫的開始時間
        // 幀動畫的持續時間
        [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^{
            weakSelf.playImageView.center = weakSelf.view.center;
        }];
        
    } completion:^(BOOL finished) {
        NSLog(@"finished");
    }];      

4. Spring動畫

  Spring Animation 是一種特殊的動畫曲線,自從 iOS 7 開始被廣泛應用在系統動畫中。

  事實上,從 iOS 7 起幾乎所有的系統動畫都用的是 Spring Animation,包括 App 檔案夾打開/關閉效果、鍵盤彈出效果、UISwitch 控件的開關效果、不同 View Controller 之間的 Push 動畫、Modal 出現和消失的動畫、Siri 的出現和消失動畫,等等

 2> Spring動畫API

+ (void)animateWithDuration:(NSTimeInterval)duration //動畫時長參數
                      delay:(NSTimeInterval)delay //動畫延遲參數
     usingSpringWithDamping:(CGFloat)dampingRatio //動畫阻尼參數,0.0~1.0,越小動畫越明顯
      initialSpringVelocity:(CGFloat)velocity //動畫初始變化速率
                    options:(UIViewAnimationOptions)options //動畫可選參數
                 animations:(void (^)(void))animations //動畫最終效果代碼塊
                 completion:(void (^)(BOOL finished))completion //動畫播放完成後執行的代碼塊      

  Spring Animation 是線性動畫或 ease-out 動畫的理想替代品。由于 iOS 本身大量使用的就是 Spring Animation,使用者已經習慣了這種動畫效果,是以使用它能使 App 讓人感覺更加自然,用 Apple 的話說就是「instantly familiar」。此外,Spring Animation 不隻能針對位置變化使用,它适用于所有可被添加動畫效果的屬性。

 3> 執行個體代碼

__weak typeof(self)weakSelf = self; 
    [UIView animateWithDuration:3.0 // 動畫時長
                          delay:0.0 // 動畫延遲
         usingSpringWithDamping:1.0 // 類似彈簧振動效果 0~1
          initialSpringVelocity:15.0 // 初始速度                        options:UIViewAnimationOptionCurveEaseInOut // 動畫過渡效果
                     animations:^{
                         CGPoint point = _imageView.center;
                         point.y += 150;
                         [_imageView setCenter:point];
                     } completion:^(BOOL finished) {  // 動畫完成後執行
                         NSLog(@"finished");
                     }];      

5. CoreAnimation動畫(CALayer動畫)

 1> CoreAnimation基本介紹

  • CoreAnimation 動畫位于 iOS 架構的 Media 層
  • CoreAnimation 動畫實作需要添加 QuartzCore.Framework
  • CoreAnimation 基本上是 Layer Animation

 2> CALayer基本介紹

 ① CALayer與UIView

  • CALayer 負責繪制,提供 UIView 需要展示的内容,不能互動。
  • UIView 負責互動,顯示 CALayer 繪制的内容。
  • UIView 是 iOS 系統中界面元素的基礎,所有的界面元素都是繼承自它。它本身完全是由 CoreAnimation 來實作的。它真正的繪圖部分,是由一個 CALayer 類來管理。UIView 本身更像是一個 CALayer 的管理器,通路它的跟繪圖和跟坐标有關的屬性,例如frame,bounds等,實際上内部都是在通路它所包含的 CALayer 的相關屬性。
  • UIView 有個重要屬性 layer ,可以傳回它的主 CALayer 執行個體。
  • UIView 的 CALayer 類似 UIView 的 子View樹形結構,也可以向它的 layer 上添加 子layer,來完成某些特殊的表示。即 CALayer 層是可以嵌套的。

 ② CALayer介紹

  • CALayer(層) 是螢幕上的一個矩形區域,在每一個 UIView 中都包含一個 根CALayer,在 UIView 上的所有視覺效果都是在這個 Layer 上進行的。
  • CALayer 外形特征主要包括:

   層的大小尺寸

   背景色

   内容(可以填充圖檔或者使用Core Graphics繪制的内容)

   矩形是否使用圓角

   矩形是否有陰影

 ③ Layer的種類

  Layer 有很多種,最常用也是最基本的是 CALayer,當然還包括其他的子類:

   CAScrollerLayer 簡化顯示層的一部分

   CATextLayer 文本層

   CAGradientLayer、CAShapeLayer等等

 3> CALayer的常用屬性

 代碼執行個體:

// 設定圓角
    self.xqImageView.layer.cornerRadius = self.xqImageView.frame.size.width / 2;
    // 影響陰影效果(注意:masksToBounds這個屬性影響layer層的陰影效果,導緻陰影不顯示)
//    self.xqImageView.layer.masksToBounds = YES;
    // 設定layer的陰影顔色
    self.xqImageView.layer.shadowColor = [UIColor lightGrayColor].CGColor;
    // 設定layer的陰影的透明度
    self.xqImageView.layer.shadowOpacity = 0.5;
    // 設定layer的陰影的偏移量
    self.xqImageView.layer.shadowOffset = CGSizeMake(20, 10);
    // 設定layer的陰影的
    self.xqImageView.layer.shadowRadius = 1;      

 4> CoreAnimation基本概念介紹

  • 渲染:當更新層改變不能立即顯示在螢幕上,當所有的層都準備好時,可以調用 setNeedsDisplay 方法來重繪顯示。
  • 坐标系統:CALayer 的坐标系統比 UIView 多了一個 anchorPoint(錨點) 屬性,使用 CGPoint 結構表示,值域是0~1,是個比例值。這個點是各種圖形變換的坐标原點,同時會更改 layer 的 position 的位置,它的預設值是{0.5,0.5},即在 layer 的中央,如下圖。
  • 動畫的運作:對UIView的subLayer(非主Layer)屬性進行更改,系統将自動進行動畫生成,動畫持續時間的預設值似乎是0.5秒。
  • 變換:要在一個層中添加一個3D或仿射變換,可以分别設定層的transform或affineTransform屬性。
  • 變形:Quartz Core的渲染能力,使二維圖像可以被自由操縱,就好像是三維的。圖像可以在一個三維坐标系中以任意角度被旋轉,縮放和傾斜。CATransform3D的一套方法提供了一些魔術般的變換效果。

 5> CoreAnimation分類

  • 隐式動畫:無需指定任何動畫的類型,僅僅改變一個屬性,然後Core Animation來決定如何及何時去做動畫。
  • 顯式動畫:對一些屬性做指定的自定義動畫,或者建立非線性動畫,比如沿着任意一條曲線移動。

 6> CoreAnimation作用

  與UIView動畫比,CoreAnimation能夠實作更多複雜、好看、高效的動畫效果

  •  陰影,圓角,帶顔色的邊框
  •  3D變換
  •  透明遮罩
  •  多級非線性動畫

 7> CoreAnimation中實作動畫的類

  • CABasicAnimation 基本單一類型的動畫
  • CAKeyframeAnimation 幀動畫,主要操作屬性有 keyPath 和 values 值組合
  • CAAnimationGroup 組合動畫,操作屬性:animations 将CAAnimation類型的動畫加入數組,FIFO隊列的方式執行

 6. CABasicAnimation

 1> CABasicAnimation關鍵屬性

  

 2> CABasicAnimation支援的方式

 3> CABasicAnimation動畫的步驟

  • 第一步:建立動畫對象
+ (instancetype)animation;      
  • 第二步:設定動畫軌迹,告訴layer層需要執行什麼樣的動畫,設定的内容為CALayer的相關屬性
@property(nullable, copy) NSString *keyPath;      

  keyPath:動畫軌迹,告訴layer層需要執行什麼樣的動畫。類型為 NSString * 但是值是系統設定好的,不能改變,改變後動畫将失去效果。例如 "position":路徑動畫;"transform":旋轉效果;"contents":改變内容等。

  • 第三步:設定動畫

  根據keyPath的值進行相應的操作

  • 第四步:設定動畫時長
@property CFTimeInterval duration;      
  • 第五步:将BasicAnimation動畫添加到CALayer上
- (void)addAnimation:(CAAnimation *)anim forKey:(nullable NSString *)key;      

  參數anim:動畫

  參數key:一個自定義的key,可以根據這個key值來删除動畫

- (void)removeAnimationForKey:(NSString *)key; // 根據key移除動畫      

 4> 執行個體代碼(具體詳見代碼注釋)

  • 路徑動畫
// 第一步:建立動畫對象
    CABasicAnimation *basicAnimation = [CABasicAnimation animation];
    // 第二步:設定動畫軌迹,告訴layer層需要執行什麼樣的動畫,設定的内容為CALayer的相關屬性
    basicAnimation.keyPath = @"position";
    // 第三步:設定初始位置和最終位置
    basicAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
    basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 200)];
    // 第四步:如果要設定動畫完成後不回到初始狀态,需要實作以下兩句代碼
    basicAnimation.removedOnCompletion = NO;
    // 設定儲存動畫狀态
    basicAnimation.fillMode = kCAFillModeForwards;
    // 第四步:設定動畫時長
    basicAnimation.duration = 6.0f;
    // 第五步:将BasicAnimation動畫添加到CALayer上
    [self.testView.layer addAnimation:basicAnimation forKey:@"basic"];      
  • 旋轉效果
CABasicAnimation *basic = [CABasicAnimation animation];
    basic.keyPath = @"transform";
    // 參數1:value值:角度 最大旋轉180°,就是會按照你設定的角度得到的效果的最短距離去旋轉,如果是360°的倍數就靜止不動
    // 參數2:x  沿x軸旋轉 縱向翻轉
    // 參數3:y  沿y軸旋轉 橫向翻轉
    // 參數4:z  沿z軸旋轉 平面旋轉
    basic.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0, 0, 1)];
    basic.duration = 2.0;
    [self.testView.layer addAnimation:basic forKey:@"transform"];      
  • 改變内容
CABasicAnimation *contents = [CABasicAnimation animation];
    contents.keyPath = @"contents";
    contents.toValue = (id)[UIImage imageNamed:@"2.jpg"].CGImage;
    contents.duration = 1.0f;
    contents.repeatCount = MAXFLOAT;  // 動畫無限循環
    contents.delegate = self;
    
    [self.testView.layer addAnimation:contents forKey:@"contents"];      

7. CAKeyframeAnimation

 1> CAKeyframeAnimation關鍵屬性

 2> 執行個體代碼(步驟同CABasicAnimation)

// 第1步:建立動畫對象
    CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animation];
    // 第2步:設定動畫軌迹
    keyFrameAnimation.keyPath = @"transform.rotation";
    // 第3步:設定旋轉的角度(弧度的計算公式:度數 / 180 * M_PI)
    keyFrameAnimation.values = @[@(0 / 180.0 * M_PI), @(90 / 180.0 * M_PI), @(180 / 180.0 * M_PI), @(270 / 180.0 * M_PI), @(360 / 180.0 * M_PI)];
    // 第4步:設定動畫的時長
    keyFrameAnimation.duration = 3;
    keyFrameAnimation.repeatCount = MAXFLOAT; // 動畫無限循環
    [self.xqImageView.layer addAnimation:keyFrameAnimation forKey:@"keyFrameAnimation"];      

8. CAAnimationGroup

 1> CAAnimationGroup關鍵屬性  

 2> 執行個體代碼

// 平移動畫
    CABasicAnimation *basic1 = [CABasicAnimation animation];
    basic1.keyPath = @"transform.translation.y";
    basic1.toValue = @(400);
    
    // 縮放
    CABasicAnimation *basic2 = [CABasicAnimation animation];
    basic2.keyPath = @"transform.scale";
    basic2.toValue = @(0.5);
    
    // 旋轉動畫
    CABasicAnimation *basic3 = [CABasicAnimation animation];
    basic3.keyPath = @"transform.rotation";
    basic3.toValue = @(2 * M_PI);
    
    // 建立管理各個動畫的動畫組
    CAAnimationGroup *group = [CAAnimationGroup animation];
    
    group.animations = @[basic1, basic2, basic3];
    
    group.duration = 3;
    
    [_xqImageView.layer addAnimation:group forKey:@"group"];      

9. CASpringAnimation

 1> CAAnimationGroup關鍵屬性

CASpringAnimation *spring = [CASpringAnimation animation];
    
    spring.keyPath = @"transform.scale";
    
    spring.fromValue = @1;
    spring.toValue = @0.25;
    
    spring.duration = 3;
    
    [_xqImageView.layer addAnimation:spring forKey:@"spring"];      

繼續閱讀