動畫基礎(chǔ)

某種意義 上蘋果已經(jīng)提供了優(yōu)美簡潔的UIView接口,對簡單需求沒必要處理CALayer,因為蘋果已經(jīng)通過UIView 的高級API 間接地使得動畫變得很簡單。
但簡單就不可避免地帶來靈活上的缺陷,UIView 沒有暴露CALayer的功能:

  1. 陰影,圓角,帶顏色的邊框
  2. 3D 變換
  3. 非矩形范圍
  4. 透明遮罩
  5. 多級非線性動畫

基礎(chǔ)屬性

UIImage *image = [UIImage imageNamed:@"1.jpg"];
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(0, 0, 300, 400);
[self.view.layer addSublayer:layer];
self.myLayer = layer;

//1.contents 屬性(id 類型)
//image.CGImage 返回一個CGImageRef 指向CGImage結(jié)構(gòu)的指針
//CGImageRef 不是Cocoa對象,而是一個Core Foundation 類型,需要 __bridge轉(zhuǎn)換
layer.contents = (__bridge id)image.CGImage;
    
//2. imageView圖片有contentMode 屬性設(shè)置圖片填充方式
layer.contentsGravity =    ;//不被拉伸
    
//3. maskToBounds 相當于 clipsToBounds 屬性來設(shè)置邊界
//默認情況下,UIView 和 CALayer 都會繪制走出邊界的內(nèi)容或子視圖
    
//4. contentsRect 允許我們在圖層邊框里顯示寄宿圖的一個子域
//它使用單位坐標(0-1),是一個相對值,是相對于寄宿圖的尺寸而言
//這個屬性可以將加載的一張圖片,切成多張圖片
layer.contentsRect = CGRectMake(0.4, 0.2, 0.3, 0.3);
    
//5. UIView 有三個布局屬性 frame,bounds,center
//CALayer 有三個布局屬性 frame,bounds,position
//frame 是外部坐標,bounds 是內(nèi)部坐標
//當操縱視圖的 frame,實際上是在改變位于視圖下方 CALayer 的 frame
//當視圖旋轉(zhuǎn)后,其frame 與 bounds 一般會不一致。因為frame 代表了覆蓋在
//圖層旋轉(zhuǎn)后整個軸對齊的矩形區(qū)域。
    
//6. 錨點
//anchorPoint默認居中(0.5,0.5),可以理解為移動圖層的把柄
//可以通過移動錨點來改變 frame,錨點改變后,其旋轉(zhuǎn)中心點也改變
    
//7. conrnerRadius屬性控制圖層的曲率,只影響背景顏色而不影響子視圖
//maskToBounds 設(shè)成 YES,才會有截取
    
//borderColor 設(shè)置邊框顏色
//borderWidth 設(shè)置邊框粗細
    
//8. shadowColor 陰影顏色
//shadowOffset 陰影方向及距離
//shadowRadius 陰影模糊度
//shadowPath 陰影路徑
//注意:開啟了masksToBounds 屬性,越界全被截剪,陰影則無法顯示
    
//9. mask 屬性本身也是一個CALayer類型
//opacity 與 alpha 相似,都會影響子圖層。
    
//10. 當有多個子視圖時,由于透明度疊加造成效果很不理想。
//shouldRasterize 屬性會將多個圖層整合成整體圖片然后設(shè)置透明度
//self.myLayer.shouldRasterize = YES;
    
    
//11. 變換
//UIView   transform 屬性,CGAffineTransform 類型(二維坐標系)
//CALayer  transform 屬性,CATransform3D 類型 (三維坐標第)
//         affineTransform 屬性,CGAffineTransform類型
    
//layer.affineTransform = CGAffineTransformMakeRotation(M_PI/4);
    
//混合變換
/*
    CGAffineTransform transform = CGAffineTransformIdentity;//初始空值
    transform = CGAffineTransformScale(transform, 0.5, 0.5);
    transform = CGAffineTransformRotate(transform, M_PI/4);
    transform = CGAffineTransformTranslate(transform, 10, 30);
    layer.affineTransform = transform;
*/
//或者
//CGAffineTransformConcat(transform, transform);
    
//旋轉(zhuǎn)
//基于最初的位置旋轉(zhuǎn)
//self.myLayer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
//基于給定的transform 旋轉(zhuǎn)
//self.myLayer.transform = CATransform3DRotate(self.myLayer.transform, M_PI, 0, 1, 0);

//**********透視效果,默認通過 m34 來改變*************
//CATransform3D transform = CATransform3DIdentity;
//transform.m34 = -1.0/500; //(500-1000是一個比較和適的值)
//transform = CATransform3DRotate(transform, M_PI_4, 1, 0, 0);
//layer.transform = transform;
    
//12. 背面,當視圖旋轉(zhuǎn)后背面不會被繪制
//self.myLayer.doubleSided = NO;

CATransition (過渡動畫)

  • CATransition動畫可以實現(xiàn)別樣的輪播圖動效
- (void)transitionAnimation{
    
    CATransition *transition = [CATransition animation];
    transition.fillMode = kCAFillModeForwards;
    transition.removedOnCompletion = YES;
    transition.startProgress = 0.0;
    transition.endProgress = 1.0;
    transition.duration = 1.0;
    transition.type = kCATransitionMoveIn;
    
    
    /*
     私有接口(慎用)
     cube   立體翻轉(zhuǎn)
     oglFlip 翻轉(zhuǎn)
     suckEffect 收縮效果
     rippleEffect 水滴波紋
     pageCurl   翻頁
     pageUnCurl
     cameralIrisHollowOpen 攝像頭打開效果
     cameraIrisHollowClose  關(guān)閉效果
     
     */
    
    /*
     公有接口
     kCATransitionFade 淡出效果
     kCATransitionMoveIn 新視圖移到舊視圖上
     kCATransitionPush  新視圖推出舊視圖
     kCATransitionReveal 移開舊視圖顯示新視圖
     */
    
    transition.subtype = kCATransitionFromLeft;
    
    /*
     kCATransitionFromRight
     kCATransitionFromLeft
     kCATransitionFromTop
     kCATransitionFromBottom
     */
    
    
    [self.imageView.layer addAnimation:transition forKey:@"transition"];
    [self setNewImage];
}

只要用手勢或計時器回調(diào)下面方法即可實現(xiàn)輪播效果

- (void)setNewImage{
    static int i = 5;
    i++;
    int imageIndex = i%5;
    NSString *imageName = [NSString stringWithFormat:@"%d.jpg",imageIndex];
    [self.imageView setImage:[UIImage imageNamed:imageName]];
}

或者

[UIView transitionWithView:_imageView
                      duration:1.0
                       options:UIViewAnimationOptionTransitionCrossDissolve
                    animations:^{
 // [self.imageView setFrame:CGRectMake(0, 0, 300, 300)];            
     [self setNewImage];
                    } completion:nil];

  • CATransition動畫實現(xiàn)簡單的轉(zhuǎn)場效果
// 在window上執(zhí)行CATransition, 即可在ViewController轉(zhuǎn)場時執(zhí)行動畫。
[self.view.window.layer addAnimation:animation forKey:@"kTransitionAnimation"];
PresentedViewController *presentedVC = [[PresentedViewController alloc] init];
[self presentViewController:presentedVC animated:NO completion:nil];
  • tabBarViewController 可以添加過渡效果
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    UIViewController *viewController1 = [[FirstViewController alloc]initWithNibName:@"FirstViewController" bundle:nil];
    UIViewController *viewController2 = [[SecondViewController alloc]initWithNibName:@"SecondViewController" bundle:nil];
    
    viewController2.title = @"第一";
    viewController1.title = @"第二";
    self.tabBarController = [[UITabBarController alloc]init];
    self.tabBarController.viewControllers = @[viewController1,viewController2];
    self.tabBarController.delegate = self;
    self.window.rootViewController = self.tabBarController;
    [self.window makeKeyAndVisible];
    
    
    return YES;
}

-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
    CATransition *transition = [CATransition animation];
    transition.type = kCATransitionFade;
    transition.duration= 3; //3秒時間過渡效果會明顯一些
    [self.tabBarController.view.layer addAnimation:transition forKey:@"transition"];
}

CAKeyframeAnimation

- (void)keyFrameAnimation{
    
      CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
      UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:self.view.center
                                                          radius:100
                                                      startAngle:0
                                                        endAngle:2 * M_PI
                                                       clockwise:YES];//順時針方向
      keyframeAnimation.path = path.CGPath;//UIKit框架轉(zhuǎn)CG框架
      keyframeAnimation.duration = 3;
      keyframeAnimation.repeatCount = 1;
      keyframeAnimation.fillMode = kCAFillModeForwards;
      keyframeAnimation.removedOnCompletion  = NO;
      keyframeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
      //這個屬性很有意思。
      keyframeAnimation.rotationMode = KCAAnimationRotateAuto;
      //*******設(shè)置value后會覆蓋path********//
      //KeyframeAnimation.values = @[ ];
      [self.layer addAnimation:keyframeAnimation forKey:@"keyframeAnimation"];
 }

- (void)addShakeAnimationForView:(UIView *)view withDuration:(NSTimeInterval)duration {
    
    CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
    CGFloat currentTx = view.transform.tx;
    
    animation.delegate = self;
    animation.duration = duration;
    animation.values = @[ @(currentTx), @(currentTx + 10), @(currentTx-8), @(currentTx + 8), @(currentTx -5), @(currentTx + 5), @(currentTx) ];
    animation.keyTimes = @[ @(0), @(0.225), @(0.425), @(0.6), @(0.75), @(0.875), @(1) ];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [self.layer addAnimation:animation forKey:@"keyframeAnimation"];
}

CABasicAnimation

/**
 *  CABsicAnimation 的實例對象只是一個數(shù)據(jù)模型,
 *  addAnimation:forKey只是將對象的copy,所以也可以添加到另外一個layer上
 *
 */

/**
 *  為什么動畫會返回原狀態(tài)
 *  添加動畫時,真正移動的并不是視圖本身,而是presentation Layer的一個緩存
 *  動畫開始,presentation Layer開始移動,原始layer隱藏
 *  動畫結(jié)束,presentation layer開始移除,原始layer顯示
 */

- (void)basicAnimation{
    
    //旋轉(zhuǎn)動畫
    CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    rotateAnimation.duration = 3.0;
    rotateAnimation.repeatCount = 100;
    rotateAnimation.autoreverses = YES;
    rotateAnimation.fromValue = [NSNumber numberWithFloat:0];
    rotateAnimation.toValue = [NSNumber numberWithFloat:6*M_PI];
    [self.layer addAnimation:rotateAnimation forKey:@"rotate"];
   
    //放大 縮小
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    scaleAnimation.duration = 3.0;
    scaleAnimation.repeatCount = 1;
    scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    scaleAnimation.toValue = [NSNumber numberWithFloat:3];
    //動畫結(jié)束后保持移動后的位置
    scaleAnimation.removedOnCompletion = NO;
    scaleAnimation.fillMode = kCAFillModeForwards;
    //設(shè)置動畫速率
    scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    /**
     *  kCAMediaTimingFunctionLinear
     *  kCAMediaTimingFunctionEaseIn  開始慢,后來快
     *  kCAMediaTimingFunctionEaseOut
     */
    
   [self.layer addAnimation:scaleAnimation forKey:@"scale"];
    //設(shè)置代理可以監(jiān)測動畫開始和結(jié)束時的動作
    scaleAnimation.delegate = self;
    
    
    //平移動畫
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.duration = 3.0;
    animation.autoreverses = YES;
    animation.repeatCount = 100;
    animation.fromValue = [NSValue valueWithCGPoint:_layer.position];
    CGPoint toPoint = _layer.position;
    toPoint.x = toPoint.x+180;
    animation.toValue = [NSValue valueWithCGPoint:toPoint];
    [self.layer addAnimation:animation forKey:@"move"];
    
}

UIView動畫

  • 動畫使用
3D變換可將圖層順序更改
動畫中更改使用transform可以快速方便地改變frame 
 [UIView animateWithDuration:0.5 animations:^{
        self.testView.layer.transform = CATransform3DMakeTranslation(10, 10, 1);
    } completion:nil];
[UIView animateWithDuration:0.5 animations:^{
        self.testView.transform = CGAffineTransformMakeTranslation(10, 10);
    } completion:nil];

-(void)normalAnimation{
    [UIView animateWithDuration:2
                          delay:1
                        options:UIViewAnimationOptionRepeat
                     animations:^{
                         [UIView setAnimationRepeatCount:3];
                         [UIView setAnimationRepeatAutoreverses:YES];
                         self.redView.center = self.view.center;
                     }
                     completion:^(BOOL finished){
                         NSLog(@"finished--%d",finished); }
     ];  
}

UIViewAnimationOptions op = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState;
[UIView animateWithDuration:0.1
                        delay:0 
                      options:op
                   animations:^{
            //view縮小
            [_view.layer setValue:@(0.5) forKeyPath:@"transform.scale"];
        } completion:^(BOOL finished) {
          
            [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
            // view放大
             [_view.layer setValue:@(1.08) forKeyPath:@"transform.scale"];
            } completion:^(BOOL finished) {
                       [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
                       //view恢得原樣
                        [_view.layer setValue:@(1) forKeyPath:@"transform.scale"];
                } completion:NULL];
            }];
        }];
  • spring動畫
-(void)springAnimation{
    
    [UIView animateWithDuration:1
                          delay:0
         usingSpringWithDamping:100//類似彈簧振動效果,越小越明顯
          initialSpringVelocity:10 //初始速度
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         [UIView setAnimationRepeatCount:5];
                         self.redView.frame = CGRectMake(50, 200, 100, 100);
                     }
                     completion:^(BOOL finished) {
                         
                     }];
}
  • 關(guān)鍵幀動畫
-(void)keyFrameAnimationView{
    [UIView animateKeyframesWithDuration:6
                                   delay:0.0
                                 options:UIViewKeyframeAnimationOptionLayoutSubviews
                              animations:^{
                                  
                                  [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.3 animations:^{
                                      self.redView.center = self.view.center;
                                  }];
                                  [UIView addKeyframeWithRelativeStartTime:0.3 relativeDuration:0.3 animations:^{
                                      self.redView.backgroundColor = [UIColor orangeColor];
                                  }];
                                  [UIView addKeyframeWithRelativeStartTime:0.6 relativeDuration:0.4 animations:^{
                                      CGRect rect= self.redView.frame;
                                      rect.size.width +=rect.size.width;
                                      rect.size.height +=rect.size.height;
                                      self.redView.frame =rect;
                                  }];
                                  //relativeStartTime
                                  //relativeDuration  都是相對時間,占總時間的占比
                                  
                              } completion:^(BOOL finished) {
                                  NSLog(@"動畫結(jié)束");
                              }];
}

UIView動畫停止

- (void)startAnimation {
 [UIView animateWithDuration:1.0
                       delay:0.0
                     options:UIViewAnimationOptionCurveLinear |
                             UIViewAnimationOptionAllowUserInteraction
                  animations:^(void) {
                         //動畫
                } completion:^(BOOL finished) {

       if(!self.canceled) {
        __weak id weakSelf = self;
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                     [weakSelf startAnimation];
                }];
         }
      }];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

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