CoreAnimation

一、CALayer常用屬性:

屬性  說明  是否支持隱式動畫 
anchorPoint 和中心點position重合的一個點,稱爲“錨點”,錨點的描述是相對於x、y位置比例而言的默認在圖像中心點(0.5,0.5)的位置
backgroundColor 圖層背景顏色 
borderColor 邊框顏色
borderWidth 邊框寬度
bounds 圖層大小
contents 圖層顯示內容,例如可以將圖片作爲圖層內容顯示
contentsRect 圖層顯示內容的大小和位置
cornerRadius 圓角半徑
doubleSided 圖層背面是否顯示,默認爲YES
frame 圖層大小和位置,不支持隱式動畫,所以CALayer中很少使用frame,通常使用bounds和position代替
hidden 是否隱藏
mask 圖層蒙版
maskToBounds 子圖層是否剪切圖層邊界,默認爲NO 是 
opacity 透明度 ,類似於UIView的alpha
position 圖層中心點位置,類似於UIView的center 
shadowColor 陰影顏色
shadowOffset 陰影偏移量
shadowOpacity 陰影透明度,注意默認爲0,如果設置陰影必須設置此屬性
shadowPath 陰影的形狀
shadowRadius 陰影模糊半徑
sublayers 子圖層
sublayerTransform 子圖層形變
transform 圖層形變
  • 在CALayer中很少使用frame屬性,因爲frame本身不支持動畫效果,通常使用bounds和position代替。 
  • CALayer中透明度使用opacity表示而不是alpha;中心點使用position表示而不是center。
  • MasksToBounds=YES之後,陰影不起作用,可以在其下面再添加一層陰影圖層,實現圓角加陰影效果。
  • CAAnimation和CALayer是鍵值編碼適應的容器類,容器類的意思是你可以爲任意的鍵設置值。即使有些鍵在CALayer中沒有聲明,你仍然可以像下面一樣設置值:

    [theLayer setValue:@50 forKey:@”someKey”];

    你可以像檢索其他鍵路徑一樣檢索任意鍵的值。比如爲了檢索之前設置的someKey鍵的值,可以像下面代碼一樣操作:

    someKeyValue = [theLayer valueForKey:@”someKey”];

二、在iOS中核心動畫分爲幾類:基礎動畫、關鍵幀動畫、動畫組、轉場動畫。各個類的關係大致如下:

CAAnimation:核心動畫的基礎類,不能直接使用,負責動畫運行時間、速度的控制,本身實現了CAMediaTiming協議。

CAPropertyAnimation:屬性動畫的基類(通過屬性進行動畫設置,注意是可動畫屬性),不能直接使用。

CAAnimationGroup:動畫組,動畫組是一種組合模式設計,可以通過動畫組來進行所有動畫行爲的統一控制,組中所有動畫效果可以併發執行。

CATransition:轉場動畫,主要通過濾鏡進行動畫效果設置。

CABasicAnimation:基礎動畫,通過屬性修改進行動畫參數控制,只有初始狀態和結束狀態。

CAKeyframeAnimation:關鍵幀動畫,同樣是通過屬性進行動畫參數控制,但是同基礎動畫不同的是它可以有多個狀態控制。

(1)、CABasicAnimation:

CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"position"];  

    basicAnimation.delegate=self;
    [basicAnimation setValue:[NSValue valueWithCGPoint:location] forKey:@"endLocation"];
    //支持鍵值編碼
    basicAnimation.fromValue=[NSValue valueWithCGPoint:_layer.position];
    basicAnimation.toValue=[NSValue valueWithCGPoint:location];
    basicAnimation.duration=.3;
    
//    basicAnimation.removedOnCompletion=FALSE;
//    basicAnimation.fillMode=kCAFillModeBoth;
    

//    fillMode的作用就是決定當前對象過了非active時間段的行爲. 比如動畫開始之前,動畫結束之後。如果是一個動畫CAAnimation,則需要將其removedOnCompletion設置爲NO,要不然fillMode不起作用.
//    kCAFillModeRemoved 這個是默認值,也就是說當動畫開始前和動畫結束後,動畫對layer都沒有影響,動畫結束後,layer會恢復到之前的狀態
//    kCAFillModeForwards 當動畫結束後,layer會一直保持着動畫最後的狀態
//    kCAFillModeBackwards 這個和kCAFillModeForwards是相對的,就是在動畫開始前,你只要將動畫加入了一個layer,layer便立即進入動畫的初始狀態並等待動畫開始.你可以這樣設定測試代碼,將一個動畫加入一個layer的時候延遲5秒執行.然後就會發現在動畫沒有開始的時候,只要動畫被加入了layer,layer便處於動畫初始狀態
//    kCAFillModeBoth 理解了上面兩個,這個就很好理解了,這個其實就是上面兩個的合成.動畫加入後開始之前,layer便處於動畫初始狀態,動畫結束後layer保持動畫最後的狀態.
    
    [_layer addAnimation:basicAnimation forKey:@"positionAnimation"];


關於動畫keyPath:

transform.scale =比例轉換

transform.scale.x =闊的比例轉換

transform.scale.y =高的比例轉換

transform.rotation.z =平面圖的旋轉

opacity =透明度

margin、zPosition、backgroundColor、cornerRadius、borderWidth、bounds、contents、contentsRect、cornerRadius、frame、hidden、mask、masksToBounds、opacity、position、shadowColor、shadowOffset、shadowOpacity、shadowRadius、

(2)、CAKeyframeAnimation:

關鍵幀分兩種類型:

//第一種方式:關鍵值
    CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
    NSArray *values=@[[NSValue valueWithCGPoint:_layer.position],
                      [NSValue valueWithCGPoint:CGPointMake(150, 140)],
                      [NSValue valueWithCGPoint:CGPointMake(120, 160)],
                      [NSValue valueWithCGPoint:CGPointMake(150, 200)],
                      [NSValue valueWithCGPoint:location]];
    keyframeAnimation.values=values;
    NSArray *times=@[[NSNumber numberWithFloat:.0],
                     [NSNumber numberWithFloat:.3],
                     [NSNumber numberWithFloat:.6],
                     [NSNumber numberWithFloat:.8],
                     [NSNumber numberWithFloat:1.0]];
    keyframeAnimation.keyTimes=times;
    keyframeAnimation.duration=4.0;
    
    [_layer addAnimation:keyframeAnimation forKey:@"keyAnimation"];</span>


//第二種方式:關鍵路徑
    CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
    
    CGMutablePathRef pathRef = CGPathCreateMutable();
    CGPathMoveToPoint(pathRef, NULL, _layer.position.x, _layer.position.y);
    CGPathAddCurveToPoint(pathRef, NULL, 100, 300, 250, 300, 175, 480);
    
    keyframeAnimation.path=pathRef;
    
    NSArray *times=@[[NSNumber numberWithFloat:.0],
                     [NSNumber numberWithFloat:.3],
                     [NSNumber numberWithFloat:.6],
                     [NSNumber numberWithFloat:.8],
                     [NSNumber numberWithFloat:1.0]];
    keyframeAnimation.keyTimes=times;
    keyframeAnimation.duration=4.0;
    
    keyframeAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    
    /** Timing function names. **/
    /*
    CA_EXTERN NSString * const kCAMediaTimingFunctionLinear         //直線勻速
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
    CA_EXTERN NSString * const kCAMediaTimingFunctionEaseIn         //減速
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
    CA_EXTERN NSString * const kCAMediaTimingFunctionEaseOut        //加速
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
    CA_EXTERN NSString * const kCAMediaTimingFunctionEaseInEaseOut  //先減速再加速
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
    CA_EXTERN NSString * const kCAMediaTimingFunctionDefault        //默認
    __OSX_AVAILABLE_STARTING (__MAC_10_6, __IPHONE_3_0);
     */
    
    
//    keyframeAnimation.calculationMode=kCAAnimationDiscrete; 
    
    /*
    CA_EXTERN NSString * const kCAAnimationLinear
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
    CA_EXTERN NSString * const kCAAnimationDiscrete
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
    CA_EXTERN NSString * const kCAAnimationPaced
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
    CA_EXTERN NSString * const kCAAnimationCubic
    __OSX_AVAILABLE_STARTING (__MAC_10_7, __IPHONE_4_0);
    CA_EXTERN NSString * const kCAAnimationCubicPaced
    __OSX_AVAILABLE_STARTING (__MAC_10_7, __IPHONE_4_0);
     */
    
    [_layer addAnimation:keyframeAnimation forKey:@"keyAnimation"];




(3)、CAAnimationGroup:

- (CABasicAnimation *)scaleAnimaion
{
    CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];
    basicAnimation.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeScale(transformScale, transformScale, 1)];
    return basicAnimation;
    
}

- (CABasicAnimation *)rotationAnimation
{
    CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    basicAnimation.toValue=[NSNumber numberWithFloat:M_PI_2*3];
    return basicAnimation;
}
- (void)groupAnimation
{
    CABasicAnimation *scaleAnimation=[self scaleAnimaion];
    CABasicAnimation *rotationAnimation=[self rotationAnimation];
    CAAnimationGroup *groupAnimation=[CAAnimationGroup animation];
    groupAnimation.animations=@[scaleAnimation,rotationAnimation];
    groupAnimation.duration=animationTime;
    groupAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    groupAnimation.autoreverses=true;
    groupAnimation.repeatCount=HUGE_VALF;
    [_layer addAnimation:groupAnimation forKey:@"groupAnimation"];
    _start=YES;
}


(4)、CATransition
    CATransition *transition =[[CATransition alloc]init];
    transition.type=kCATransitionMoveIn;   
//對於蘋果官方沒有公開的動畫類型,只能用字符串來表示,並沒有常量定義。//  transition.type=@"cube"; transition.type=kCATransitionMoveIn ; transition.subtype=kCATransitionFromRight; [_imgView.layer addAnimation:transition forKey:@"Transition"];


動畫類型 說明 對應常量 是否支持方向設置
公開API      
fade 淡出效果 kCATransitionFade
movein 新視圖移動到舊視圖上 kCATransitionMoveIn
push 新視圖推出舊視圖 kCATransitionPush
reveal 移開舊視圖顯示新視圖 kCATransitionReveal
私有API   私有API只能通過字符串訪問  
cube 立方體翻轉效果
oglFlip 翻轉效果
suckEffect 收縮效果
rippleEffect 水滴波紋效果
pageCurl 向上翻頁效果
pageUnCurl 向下翻頁效果
cameralIrisHollowOpen 攝像頭打開效果
cameraIrisHollowClose 攝像頭關閉效果

另外對於支持方向設置的動畫類型還包含子類型:

動畫子類型 說明
kCATransitionFromRight 從右側轉場
kCATransitionFromLeft 從左側轉場
kCATransitionFromTop 從頂部轉場
kCATransitionFromBottom 從底部轉場

注:可以實現無限循環圖片瀏覽器

三、動畫相關重點:

(1)、CATransaction :

CATransaction 事務類,可以對多個layer的屬性同時進行修改.它分隱式事務,和顯式事務.

區分隱式動畫和隱式事務:隱式動畫通過隱式事務實現動畫 。

區分顯式動畫和顯式事務:顯式動畫有多種實現方式,顯式事務是一種實現顯式動畫的方式。 

除顯式事務外,任何對於CALayer屬性的修改,都是隱式事務.這樣的事務會在run-loop中被提交.

//設置變化動畫過程是否顯示,默認爲YES不顯示
    [CATransaction setDisableActions:NO];
    //設置圓角
    layer.cornerRadius = (layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
    //設置透明度
    layer.opacity = (layer.opacity == 1.0f) ? 0.5f : 1.0f;

顯示事務通過明確的調用begin,commit來提交動畫

[CATransaction begin];
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    layer.cornerRadius = (layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
    [CATransaction commit];
    //上面的動畫並不會立即執行,需要等最外層的commit
    [NSThread sleepForTimeInterval:10];
    //顯式事務默認開啓動畫效果,kCFBooleanTrue關閉
    [CATransaction setValue:(id)kCFBooleanFalse
                     forKey:kCATransactionDisableActions];
    //動畫執行時間
    [CATransaction setValue:[NSNumber numberWithFloat:10.0f] forKey:kCATransactionAnimationDuration];
    //[CATransaction setAnimationDuration:[NSNumber numberWithFloat:5.0f]];
    anotherLayer.cornerRadius = (anotherLayer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
    [CATransaction commit];

(2)、動畫暫停與繼續:

- (IBAction)continueAnimation:(id)sender {
     if (_layer.speed==0) {
          CFTimeInterval beginTime=CACurrentMediaTime()-_layer.timeOffset;
          _layer.timeOffset=0;
          _layer.beginTime=beginTime;
          _layer.speed=1;
     }
}

- (IBAction)pauseAnimation:(id)sender {
    if (_layer.speed==1) {
        _layer.timeOffset=[_layer convertTime:CACurrentMediaTime() fromLayer:nil];
        _layer.speed=0;
    }
}
(3)、動畫定時器:
- (void)viewDidLoad {
    [super viewDidLoad];
    
    _index=0;
    CADisplayLink *displayLink=[CADisplayLink displayLinkWithTarget:self selector:@selector(bgColorChange:)];
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    // Do any additional setup after loading the view.
}


-(void)bgColorChange:(CADisplayLink *)displayLink
{
    _index++;
    if (_index==400) {
        [displayLink invalidate];
    }
    int value_r=arc4random()%255;
    int value_g=arc4random()%255;
    int value_b=arc4random()%255;
    self.view.backgroundColor=[UIColor colorWithRed:value_r/255.0 green:value_g/255.0 blue:value_b/255.0 alpha:1];
}
(4)、drawRect:與drawLayer:inContext、drawInContext:

KCALayer.m文件

#import "KCALayer.h"
@implementation KCALayer
- (void)drawInContext:(CGContextRef)ctx
{
    NSLog(@"3-drawInContext:");
    NSLog(@"CGContext:%@",ctx);
}
@end
KCView.m文件

#import "KCView.h"
#import "KCALayer.h"
@implementation KCView
- (instancetype)initWithFrame:(CGRect)frame
{
    if (self=[super initWithFrame:frame]) {
        KCALayer *layer=[[KCALayer alloc]init];
        layer.bounds=CGRectMake(0, 0, 185, 185);
        layer.position=CGPointMake(160, 284);
        layer.backgroundColor=[UIColor colorWithRed:0 green:146/255.0 blue:1.0 alpha:1.0].CGColor;
        [layer setNeedsDisplay];
        [self.layer addSublayer:layer];
    }
    return self;
}
-(void)drawRect:(CGRect)rect{
    NSLog(@"2-drawRect:");
    NSLog(@"CGContext:%@",UIGraphicsGetCurrentContext());//得到的當前圖形上下文正是drawLayer中傳遞的
    [super drawRect:rect];
    
}
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
NSLog(@"1-drawLayer:inContext:");  NSLog(@"CGContext:%@",ctx);[super drawLayer:layer inContext:ctx];
@end


(5)、給CALayer添加圖片:

-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
    //    NSLog(@"%@",layer);//這個圖層正是上面定義的圖層
    UIImage *image=[UIImage imageNamed:@"touxiang.jpg"];
    //注意這個位置是相對於圖層而言的不是屏幕
    CGContextDrawImage(ctx, CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT), image.CGImage);
}
layer.contents = (id)[UIImage imageNamed:@"view_BG.png"].CGImage; // 給圖層添加背景圖片  


drawInContext

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章