天天看點

iOS之CALayer與核心動畫(一)

01-CALayer的基本操作.

1.CALayer簡介:
    CALayer我們又稱它叫做層.
    在每個UIView内部都有一個layer這樣一個屬性.
    UIView之是以能夠顯示,就是因為它裡面有這個一個層,才具有顯示的功能.
    我們通過操作CALayer對象,可以很友善地調整UIView的一些外觀屬性.
    可以給UIView設定陰影,圓角,邊框等等...

2.操作layer改變UIView外觀.

    2.1.設定陰影
    預設圖層是有陰影的, 隻不過,是透明的
    _RedView.layer.shadowOpacity = 1;
    設定陰影的圓角
    _RedView.layer.shadowRadius  =10;
    設定陰影的顔色,把UIKit轉換成CoreGraphics架構,用.CG開頭
    _RedView.layer.shadowColor = [UIColor blueColor].CGColor;

    2.2.設定邊框
    設定圖層邊框,在圖層中使用CoreGraphics的CGColorRef
    _RedView.layer.borderColor = [UIColor whiteColor].CGColor;
    _RedView.layer.borderWidth = 2;

    2.3.設定圓角
    圖層的圓角半徑,圓角半徑為寬度的一半, 就是一個圓
    _RedView.layer.cornerRadius = 50;

3.操作layer改變UIImageView的外觀.

    設定圖形邊框
    _imageView.layer.borderWidth = 2;
    _imageView.layer.borderColor = [UIColor whiteColor].CGColor;


    設定圖檔的圓角半徑
    _imageView.layer.cornerRadius = 50;
    裁剪,超出裁剪區域的部分全部裁剪掉
    _imageView.layer.masksToBounds = YES;
    注意:UIImageView當中Image并不是直接添加在層上面的.這是添加在layer當中的contents裡.
    我們設定層的所有屬性它隻作用在層上面.對contents裡面的東西并不起作用.是以我們看不到圖檔有圓角的效果.
    想要讓圖檔有圓角的效果.可以把masksToBounds這個屬性設為YES,
    當設為YES,把就會把超過根層以外的東西都給裁剪掉.

4.layer的 CATransform3D屬性.

  隻有旋轉的時候才可以看出3D的效果.
  旋轉
  x,y,z 分别代表x,y,z軸.
  CATransform3DMakeRotation(M_PI, 1, 0, 0);
  平移
  CATransform3DMakeTranslation(x,y,z)
  縮放
  CATransform3DMakeScale(x,y,z);

  可以通過KVC的方式進行設定屬性.
  但是CATransform3DMakeRotation它的值,是一個結構體, 是以要把結構轉成對象.
  NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 0, 0)];
  [_imageView.layer setValue:value forKeyPath:@"transform.scale"];


  什麼時候用KVC?
  當需要做一些快速縮放,平移,二維的旋轉時用KVC.
  比如: [_imageView.layer setValue:@0.5 forKeyPath:@"transform.scale"];
  快速的進行縮放.
  後面forKeyPath屬性值不是亂寫的.蘋果文檔當中給了相關的屬性.
           

02-自定義CALayer

1.如何自定義Layer.
自定義CALayer的方式建立UIView的方式非常相似.
 CALayer *layer = [CALayer layer];
 layer.frame = CGRectMake(50, 50, 100, 100);
 layer.backgroundColor = [UIColor redColor].CGColor;
 [self.view.layer addSublayer:layer];

給layer設定圖檔.
layer.contents = (id)[UIImage imageNamed:@"阿狸頭像"].CGImage;

2.關于CALayer的疑惑?
  為什麼要使用CGImageRef、CGColorRef?
  為了保證可移植性,QuartzCore不能使用UIImage、UIColor,隻能使用CGImageRef、CGColorRef

  UIView和CALayer都能夠顯示東西,該怎樣選擇?
  對比CALayer,UIView多了一個事件處理的功能。也就是說,CALayer不能處理使用者的觸摸事件,而UIView可以
  如果顯示出來的東西需要跟使用者進行互動的話,用UIView;
  如果不需要跟使用者進行互動,用UIView或者CALayer都可以
  CALayer的性能會高一些,因為它少了事件處理的功能,更加輕量級
           

03-position和anchorPoint

position和anchorPoint是CAlayer的兩個屬性.
我們以前修改一個控件的位置都是能過Frame的方式進行修改.
現在利用CALayer的position和anchorPoint屬性也能夠修改控件的位置.
這兩個屬性是配合使用的.
position:它是用來設定目前的layer在父控件當中的位置的.
          是以它的坐标原點.以父控件的左上角為(0.0)點.

anchorPoint:它是決點CALayer身上哪一個點會在position屬性所指的位置
           anchorPoint它是以目前的layer左上角為原點(0.0)
           它的取值範圍是0~1,它的預設在中間也就是(0.5,0.5)的位置.
           anchorPoint又稱錨點.就是把錨點定到position所指的位置.

兩者結合使用.想要修改某個控件的位置,我們可以設定它的position點.
           設定完畢後.layer身上的anchorPoint會自動定到position所在的位置.
           

04-隐式動畫.

什麼是隐式動畫?
了解什麼是隐式動畫前,要先了解是什麼根層和非根層.
根層:UIView内部自動關聯着的那個layer我們稱它是根層.
非根層:自己手動建立的層,稱為非根層.

隐式動畫就是當對非根層的部分屬性進行修改時, 它會自動的産生一些動畫的效果.
我們稱這個預設産生的動畫為隐式動畫.

如何取消隐式動畫?
首先要了解動畫底層是怎麼做的.動畫的底層是包裝成一個事務來進行的.
什麼是事務?
很多操作綁定在一起,當這些操作執行完畢後,才去執行下一個操作.

開啟事務
[CATransaction begin];
設定事務沒有動畫
[CATransaction setDisableActions:YES];
設定動畫執行的時長
[CATransaction setAnimationDuration:2];


送出事務
[CATransaction commit];
           

05-時鐘效果

1.搭建界面.
    分析界面.
    界面上時針,分針,秒針不需要與使用者進行互動.是以都可以使用layer方式來做.
    做之前要觀察時針在做什麼效果.
    是根據目前的時間,繞着表盤的中心點進行旋轉.
    要了解一個非常重要的知識點.無論是旋轉,縮放它都是繞着錨點.進行的.

    要想讓時針,分針,稱針顯示的中間,還要繞着中心點進行旋轉.
    那就要設定它的position和anchorPoint兩個屬性.


    建立秒針
    CALayer *layer = [CALayer layer];
     _secLayer = layer;
    layer.bounds = CGRectMake(0, 0, 1, 80);
    layer.anchorPoint = CGPointMake(0.5, 1);
    layer.position = CGPointMake(_clockView.bounds.size.width * 0.5,    _clockView.bounds.size.height * 0.5);
    layer.backgroundColor = [UIColor redColor].CGColor;
    [_clockView.layer addSublayer:layer];


 2.讓秒針開始旋轉.

    讓秒針旋轉.是以要計算目前的旋轉度是多少?
    目前的旋轉角度為:目前的時間 * 每秒旋轉多少度.

    計算每一秒旋轉多少度.
    60秒轉一圈360度
    360 除以60就是每一秒轉多少度.每秒轉6度.

    擷取目前的時間
    建立月曆類
    NSCalendar *calendar = [NSCalendar currentCalendar];
    把月曆類轉換成一個日期元件
    日期元件(年,月,日,時,分,秒)
    component:日期元件有哪些東西組成,他是一個枚舉,裡面有年月日時分秒
    fromDate:目前的日期
    NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond
                                           fromDate:[NSDate date]];

    我們的秒就是儲存在日期元件裡面,它裡面提供了很多get方法.
    NSInteger second = cmp.second;

    那麼目前秒針旋轉的角度就是
    目前的秒數乘以每秒轉多少度.
    second * perSecA 
    還得要把角度轉換成弧度.

    因為下面分針,時針也得要用到, 就把它抽出一個速參數的宏.
    #define angle2Rad(angle) ((angle) / 180.0 * M_PI)

    讓它每隔一秒旋轉一次.是以添加一個定時器.
    每個一秒就調用,旋轉秒針
     - (void)timeChange{
     擷取目前的秒數
     建立月曆類
     NSCalendar *calendar = [NSCalendar currentCalendar];
     把月曆類轉換成一個日期元件
     日期元件(年,月,日,時,分,秒)
     component:日期元件有哪些東西組成,他是一個枚舉,裡面有年月日時分秒
     fromDate:目前的日期
     NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond 
                                          fromDate:[NSDate date]];
     我們的秒就是儲存在日期元件裡面,它裡面提供了很多get方法.
     NSInteger second = cmp.second;
     秒針旋轉多少度.
     CGFloat angel = angle2Rad(second * perSecA);
     旋轉秒針
     self.secondL.transform = CATransform3DMakeRotation(angel, 0, 0, 1);
     }
    運作發現他會一下隻就調到某一個時間才開始旋轉
    一開始的時候就要來到這個方法,擷取目前的秒數把它定位好.
    要在添加定時器之後就調用一次timeChange方法.


    3.添加分針

    快速拷貝一下,然後添加一個分針成員屬性.
    修改寬度,修改顔色
    也得要讓它旋轉,
    要算出每分鐘轉多少度
    轉60分鐘剛好是一圈
    是以每一分鐘也是轉6度.

    擷取目前多少分?
    同樣是在日期元件裡面獲得
    裡面有左移符号,右移符号.他就可以用一個并運算
    現在同時讓他支援秒數和分 後面直接加上一個 |
     NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond | 
                                        NSCalendarUnitMinute 
                                        fromDate:[NSDate date]];

    CGFloat minueteAngel = angle2Rad(minute * perMinuteA);
    self.minueL.transform = CATransform3DMakeRotation(minueteAngel, 0, 0, 1);

    4.添加時針

     同樣複制之前的,添加一個小時屬性
     小時轉多少度
     目前是多少小時,再計算先每一小時轉多少度.
     12個小時轉一圈. 360除以12,每小時轉30度
     時針旋轉多少度
     CGFloat hourAngel = angle2Rad(hour * perHourA);
     旋轉時針
     self.hourL.transform = CATransform3DMakeRotation(hourAngel, 0, 0, 1);

    直接這樣寫會有問題
    就是沒轉一分鐘,小時也會移動一點點
    接下來要算出,每一分鐘,小時要轉多少度
    60分鐘一小時.一小時轉30度.
    30 除以60,就是每一分鐘,時針轉多少度.0.5

    時針旋轉多少度
    CGFloat hourAngel = angle2Rad(hour * perHourA + minute * perMinuteHourA);
    旋轉時針
    self.hourL.transform = CATransform3DMakeRotation(hourAngel, 0, 0, 1);
           

06-CABasicAnimation基礎核心動畫

核心動畫之作用在層上面.
動畫的本質是改圖層的某一個屬性.
CABasicAnimation *anim = [CABasicAnimation animation];
圖層有那些屬性,這裡才能寫那些屬性.
anim.keyPath = @"transform.scale";
anim.toValue = @0.5;
告訴動畫完成的時候不要移除
anim.removedOnCompletion = NO;
儲存動畫最前面的效果.
anim.fillMode = kCAFillModeForwards;
把動畫添加到層上面.
[_redView.layer addAnimation:anim forKey:nil];
           

07-心跳效果

思路:就是讓一張圖檔做一個放大縮放小的動畫.

代碼實作:

CABasicAnimation *anim =[CABasicAnimation  animation];
設定縮放屬性
anim.keyPath = @"transform.scale";
縮放到最小
anim.toValue = @0;
設定動畫執行的次數
anim.repeatCount = MAXFLOAT;
設定動畫執行的時長
anim.duration = 0.25;
設定動畫自動反轉(怎麼去, 怎麼回)
anim.autoreverses = YES;
添加動畫
[self.heartView.layer addAnimation:anim forKey:nil];
           

08-圖檔抖動(幀動畫)

1.幀動畫介紹:
    CAKeyframeAnimation它可以在多個值之間進行動畫.
    設定多值之間的屬性為:
    後面是一個數組,就是要設定的多個值.
    anim.values = @[];

    它還可以根據一個路徑做動畫.
    anim.path = 自己建立的路徑.

2.圖檔抖動思路:
    其實就是做一個左右旋轉的動畫.先讓它往左邊旋轉-5,再往右邊旋轉5度,再從5度旋轉到-5度.
    就會有左右搖擺的效果了.

    具體實作代碼
    建立幀動畫
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
    設定動畫屬性為旋轉
    anim.keyPath = @"transform.rotation";
    設定屬性值為多個屬性
    anim.values = @[@(angle2radio(-5)),@(angle2radio(5)),@(angle2radio(-5))];
    設定動畫執行次數
    anim.repeatCount = MAXFLOAT;
    添加動畫
    [_imageView.layer addAnimation:anim forKey:nil];

3.根據圓形的路徑做移動的效果.
    建立路徑
    UIBezierPath *path = [UIBezierPath 
                          bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 100)];
   [path addLineToPoint:CGPointMake(200, 500)];

   把路徑設為動畫的屬性
   anim.path = path.CGPath;
           

09-轉場動畫

1.什麼是轉場動畫?
    就是從一個場景轉換到另一個場景,像導航控制器的push效果,就是一個轉場.

2.如何建立轉場動畫
  建立轉場動畫
  CATransition *anim = [CATransition animation];
  設定轉場類型
  anim.type = @"cube";
  anim.duration = 1;
  設定轉場的方向
  anim.subtype = kCATransitionFromLeft;
  設定動畫的開始位置
  anim.startProgress = 0.5;
  設定動畫的結束位置
  anim.endProgress  =0.8;
  添加動畫.了
 [_imageV.layer addAnimation:anim forKey:nil];


 要執行動畫的代碼稱為轉場代碼.
 轉場動畫要和轉場代碼寫在同一個方法當中才有動畫效果.

3.UIView進行轉場動畫

   [UIView transitionWithView:self.imageV duration:1 
    options:UIViewAnimationOptionTransitionFlipFromRight 
    animations:^{
        轉場代碼
    } completion:^(BOOL finished) {
        動畫執行完畢時調用.
    }];

    使用UIView轉場的類型比較少.
           

10-動畫組

可以同時執行多個動畫.
建立組動畫
CAAnimationGroup *group = [CAAnimationGroup animation];

平移
CABasicAnimation *anim = [CABasicAnimation animation];
anim.keyPath = @"position.y";
anim.toValue = @400;

縮放
CABasicAnimation *scaleAnim = [CABasicAnimation  animation];
scaleAnim.keyPath = @"transform.scale";
scaleAnim.toValue = @0.5;
設定動畫組屬性
group.animations = @[anim,scaleAnim];

group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
添加組動畫
[self.redView.layer addAnimation:group forKey:nil];

使用動畫組的好處,不需要每次都去添加動畫,設定動畫完成時的屬性.
隻需要把要執行的動畫,添加到動畫組的animations數組當中即可,
最後把組動畫添加到層上面,就會自動執行數組當中的動畫.
動畫完成時設定的屬性也隻需要設定一次.
           

11.UIView與核心動畫對比?

1.UIView和核心動畫差別?
   核心動畫隻能添加到CALayer
   核心動畫一切都是假象,并不會改變真實的值。

2.什麼時候使用UIView的動畫?
  如果需要與使用者互動就使用UIView的動畫.
  不需要與使用者互動可以使用核心動畫

3.什麼場景使用核心動畫最多?
  在轉場動畫中,核心動畫的類型比較多
  根據一個路徑做動畫,隻能用核心動畫(幀動畫)
  動畫組:同時做多個動畫