iOS 核心動畫 Core Animation淺談

代碼地址以下:
http://www.demodashi.com/demo/11603.htmlhtml

前記

關於實現一個iOS動畫,若是簡單的,咱們能夠直接調用UIView的代碼塊來實現,雖然使用UIView封裝的方法很方便,可是這隻能用於一些簡答的動畫,若是是一些複雜的動畫呢?這就不得不去研究下核心動畫Core Animation(包含在Quartz Core框架中)了。這這以前咱們必須瞭解,CALayer就包含在Quartz Core框架中,這是一個跨平臺的框架,既能夠用在iOS中又能夠用在Mac OS X中。在使用Core Animation開發動畫的本質就是將CALayer中的內容轉化爲位圖從而供硬件操做,因此要熟練掌握動畫操做必須熟悉CALayer,關於CALayer就不在這裏講了。今天主要是分析核心動畫,iOS 中的核心動畫又分爲下面幾種:基礎動畫、關鍵幀動畫、動畫組、轉場動畫、彈簧動畫。下面咱們先來了解下各個動畫之間的關係spring

core_animation.jpeg

動畫簡介
CAAnimation
@interface CAAnimation : NSObject
    <NSCoding, NSCopying, CAMediaTiming, CAAction>
{
@private
  void *_attr;
  uint32_t _flags;
}

這是核心動畫的基類,不能直接使用,主要負責動畫的時間、速度等,從上面能夠看出是準守CAMediaTiming協議的。併發

CAPropertyAnimation

屬性動畫的基礎類,繼承自CAAnimation,不能直接使用。何謂屬性動畫呢?即經過修改屬性值就能夠產生動畫效果。框架

CAAnimationGroup

動畫組,繼承自CAAnimation,顧名思義就是一種組合動畫,能夠經過動畫組來進行全部動畫行爲的統一控制,組中全部動畫效果能夠併發執行。函數

CATransition

轉場動畫,繼承自CAAnimation,主要是經過濾鏡來進行動畫的效果設置動畫

CABasicAnimation

基礎動畫,繼承自CAPropertyAnimation,經過屬性控制動畫的參數,只要初始狀態和結束狀態ui

CAKeyframeAnimation

關鍵幀動畫,繼承自CAPropertyAnimation,也是經過屬性控制動畫參數,可是與基礎動畫不一樣的是有多個控制狀態,而且能夠經過path來實現動畫url

CASpringAnimation

彈簧動畫,是在iOS 9中引入的,繼承自CABasicAnimation,用於製做彈簧動畫3d

動畫使用

在使用動畫以前,先補充個知識點---UIBezierPath, 這在動畫使用的過程當中會常常用到code

核心動畫

要使用核心動畫,咱們必須先了解下其屬性,這裏咱們先看其遵照的協議<CAMediaTiming>

屬性 說明
beginTime 指定動畫開始的時間。開始延遲幾秒的話,設置爲CACurrentMediaTime() + 秒數 的方式便可
duration 動畫的時長
speed 動畫的速度
timeOffset 詳細說明
repeatCount 動畫重複的次數,若是要一直持續設置爲HUGE_VALF便可
repeatDuration 設置動畫的時間。在該時間內動畫一直執行,不計次數
autoreverses 動畫結束時是否執行逆動畫
fillMode 分四種狀況,分別爲kCAFillModeForwardskCAFillModeBackwardskCAFillModeBothkCAFillModeRemoved,決定當前對象在非active時間段的行爲,好比動畫開始以前或者動畫結束之

CAAnimation屬性

屬性 說明
timingFunction 速度控制函數,控制動畫運行的節奏
removedOnCompletion 默認爲YES,表明動畫執行完畢後就從圖層上移除,圖形會恢復到動畫執行前的狀態。若是想讓圖層保持顯示動畫執行後的狀態,那就設置爲NO,不過還要設置fillModekCAFillModeForwards

關於fillMode的四種狀況:

  • kCAFillModeRemoved 默認值,動畫結束後,layer會恢復到以前的狀態

  • kCAFillModeForwards 當動畫結束後,layer會一直保持着動畫最後的狀態,而removedOnCompletion的默認屬性值是 YES,因此爲了使動畫結束以後layer保持結束狀態,應將removedOnCompletion設置爲NO

  • kCAFillModeBackwards 在動畫開始前,只須要將動畫加入了一個layer,layer便當即進入動畫的初始狀態並等待動畫開始。

  • kCAFillModeBoth 這個其實就是上面兩個的合成,動畫加入後開始以前,layer便處於動畫初始狀態,動畫結束後layer保持動畫最後的狀態

關於速度CAMediaTimingFunction控制的四種狀況

  • kCAMediaTimingFunctionLinear(線性):勻速,給你一個相對靜態的感受

  • kCAMediaTimingFunctionEaseIn(漸進):動畫緩慢進入,而後加速離開

  • kCAMediaTimingFunctionEaseOut(漸出):動畫全速進入,而後減速的到達目的地

  • kCAMediaTimingFunctionEaseInEaseOut(漸進漸出):動畫緩慢的進入,中間加速,而後減速的到達目的地。這個是默認的動畫行爲。

屬性動畫

從上圖中咱們知道,屬性動畫是繼承自核心動畫,在其API中咱們能夠看到有以下函數和屬性

+ (instancetype)animationWithKeyPath:(nullable NSString *)path;

@property(nullable, copy) NSString *keyPath;

其中都有keyPath,這又是什麼呢?這就是屬性動畫與動畫組和轉場動畫不一樣之處。經過指定CALayer的一個屬性名稱爲keyPath(NSString類型),而且對CALayer的這個屬性的值進行修改,達到相應的動畫效果。好比,指定@"opacity"keyPath,就修改CALayeropacity屬性的值,以達到透明度變化的動畫效果
下面咱們列舉一些經常使用的animationWithKeyPath

經常使用值 說明 使用方式
transform 3D變換 [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 0)],直接進行3D變換
transform.scale 縮放 @(1.5) ,放大1.5倍
transform.scale.x 寬度縮放 @(1.5) ,寬放大1.5倍
transform.scale.y 高度縮放 @(1.5) ,高放大1.5倍
transform.rotation.x 圍繞x軸旋轉 @(M_PI) ,x軸旋轉180度
transform.rotation.y 圍繞y軸旋轉 @(M_PI) ,y軸旋轉180度
transform.rotation.z 圍繞z軸旋轉 @(M_PI) ,z軸旋轉180度
position 位置(中心點的改變) [NSValue valueWithCGPoint:CGPointMake(100, 100)],中心點變爲(100,100)
opacity 透明度 @(0.5) ,透明度變爲0.5
bounds 大小的改變 中心點保持不變 [NSValue valueWithCGRect:CGRectMake(0, 0, 300, 300)],大小變爲(300,300)
cornerRadius 圓角的設置 @(5) ,圓角設置爲5
backgroundColor 背景顏色變換 (id)[UIColor redColor].CGColor,背景改成紅色
contents 能夠改變layer展現的圖片 (id)[UIImage imageNamed:@"12.png"].CGImage,將UIView的展現圖片改成12.png
strokeStart 從起始點開始變化 fromValue = 0toValue = 1,爲CAShapeLayer的屬性
strokeEnd 從結束的位置開始變化 fromValue = 1toValue = 0.5,爲CAShapeLayer的屬性
path 根據路徑來改變 fromValue = (__bridge id)(start.CGPath);toValue = (__bridge id)((end.CGPath))
基礎動畫

基礎動畫是繼承自屬性動畫,因此在使用的時候,咱們最主要的就是經過屬性來控制動畫,好比設置初始值、結束值,固然還有核心動畫的其餘屬性。

- (void)showAnimation
{
    CAShapeLayer * circle = [CAShapeLayer layer];
    circle.frame = self.view.bounds;
    
    //
    UIBezierPath  * circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds)) radius:self.normalSize.width/2 -1 startAngle:0 endAngle:2*M_PI clockwise:YES];
    
    circle.path = circlePath.CGPath;
    circle.strokeColor = [UIColor blueColor].CGColor;
    circle.fillColor = nil;
    [self.view.layer addSublayer:circle];
    
    //經過圓的strokeStart 改變來進行改變
    CABasicAnimation * strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
    strokeStartAnimation.fromValue = @(0.2);
    strokeStartAnimation.toValue = @(0);
    
    //經過圓的strokeEnd 改變來進行改變
    CABasicAnimation * strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    strokeEndAnimation.fromValue = @0.5;
    strokeEndAnimation.toValue = @(1.0);
    
    //經過圓的transform.rotation.z 改變來進行改變
    CABasicAnimation * rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.fromValue = @(0);
    rotationAnimation.toValue = @(-M_PI * 2);
    
    //組合動畫
    CAAnimationGroup * group = [CAAnimationGroup animation];
    group.duration = 5;
    group.removedOnCompletion = NO;
    group.fillMode = kCAFillModeForwards;
    group.animations = @[strokeStartAnimation,strokeEndAnimation,rotationAnimation];
    [circle addAnimation:group forKey:nil];
    
}

在上面的基礎動畫代碼中,我只用了最基礎的兩個屬性,fromValuetoValue,而其它屬性呢?因爲後面用到了動畫組,因此講其它屬性在動畫組進行了設置。[circle addAnimation:group forKey:nil];這句代碼中,key我設置的爲nil,若是不設置爲nil的時候,是什麼意思呢?這個其實就是咱們的動畫設置了一個key,能夠用來區別是哪個動畫,在後面我會舉例說明。
上面代碼對應的效果以下:

baseAnimation.gif

關鍵幀動畫

關鍵幀動畫也是屬性動畫,與基礎動畫最主要不一樣的是在兩個參數上,NSArray *valuesCGPathRef path,經過這個咱們能夠知曉,關鍵幀動畫能夠設置多個控制狀態
以下:

//用value的方式進行展現動畫
- (void)showKeyFrameAnimationWithValues
{
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    NSValue *key1 = [NSValue valueWithCGPoint:_beginPoint];
    NSValue *key2 = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
    NSValue *key3 = [NSValue valueWithCGPoint:CGPointMake(150, 50)];
    NSValue *key4 = [NSValue valueWithCGPoint:CGPointMake(300, 250)];
    animation.values = @[key1,key2,key3,key4];
    animation.duration = 5.0;
    animation.delegate = (id)self;
//    animation.autoreverses = true;//是否按路徑返回
//    animation.repeatCount = HUGE;//是否重複執行
    animation.removedOnCompletion = NO;//執行後移除動畫
    animation.fillMode = kCAFillModeForwards;
    
    //存儲位置
    [animation setValue:key4 forKey:@"keyframeAnimationLocation"];
    
    [_fishImageView.layer addAnimation:animation forKey:@"keyframeAnimation_fish"];
}

並且還能夠設置路徑,這也是其最大的特色
以下:

//用CGPathRef的方式進行展現動畫
- (void)showKeyFrameAnimationWithPath
{
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:_fishImageView.layer.position];
    //三次貝塞爾曲線
    [path addCurveToPoint:CGPointMake(300, 200) controlPoint1:CGPointMake(150, 400) controlPoint2:CGPointMake(230, -100)];
    
    animation.path = path.CGPath;
    animation.duration = 5.0;
    animation.delegate = (id)self;
    [_fishImageView.layer addAnimation:animation forKey:@"keyframeAnimation_path_fish"];
}

效果以下,這裏就暫時只給出values的效果

keyanimation.gif

在上面的兩個方法中,對layer設置了兩個不一樣的key,分別爲keyframeAnimation_fishkeyframeAnimation_path_fish
前面我提到過,經過這個能夠判斷是哪種動畫,這裏咱們在動畫結束的地方進行區分一下

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    if ([anim isEqual:[_fishImageView.layer animationForKey:@"keyframeAnimation_fish"]])
    {
//        [CATransaction begin];
//        //禁用隱式動畫
//        [CATransaction setDisableActions:YES];
        
        _fishImageView.layer.position = [[anim valueForKey:@"keyframeAnimationLocation"] CGPointValue];
   
//        //提交事務
//        [CATransaction commit];
    }
    else if ([anim isEqual:[_fishImageView.layer animationForKey:@"keyframeAnimation_path_fish"]])
    {
    
    }
}
動畫組

動畫組其實很簡單,就是將許多動畫組合在一塊兒
在上面的基礎動畫中,我也用到了動畫組,下面再貼上一組動畫組合效果

//發射
- (void)launchAnimation
{
    CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
    animation1.fromValue = @(1.0);
    animation1.toValue = @(1.5);
    
    CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"];
    animation2.fromValue = @(1.0);
    animation2.toValue = @(1.5);
    
    CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"position"];
    animation3.fromValue = [NSValue valueWithCGPoint:_ballLayer.position];
    animation3.toValue = [NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width - (30 * 1.3)/2.0 , _ballLayer.position.y - 200)];
    
    
    CAAnimationGroup *anima = [CAAnimationGroup animation];
    anima.animations = @[animation1, animation2,animation3];
    anima.duration = 1.0;
    anima.delegate = (id)self;
    anima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    anima.fillMode = kCAFillModeForwards;
    anima.removedOnCompletion = NO;
    
    [_ballLayer addAnimation:anima forKey:@"group_launch"];
}

在後面的demo裏有完整的代碼,這裏只是截取了部分代碼
效果以下:

groupanimation.gif

轉場動畫

在瞭解轉場動畫以前,咱們先了解其兩個參數,經過這些參數,咱們就能很清楚的瞭解其效果

  • type轉場類型
轉場動畫類型 說明 常量 是否支持方向設置
公開API
fade 淡出 kCATransitionFade
movein 新視圖移動到舊視圖上面 kCATransitionMoveIn
push 新視圖退出舊視圖 kCATransitionPush
reveal 移開舊視圖顯示新的 kCATransitionReveal
私有API 蘋果未公開的類型,可是目前仍是能夠用的 私有API只能經過下面的字符串進行訪問
cube 立體翻轉
oglFlip 翻轉
suckEffect 收縮
rippleEffect 水滴波紋效果
pageCurl 向上翻頁效果
pageUnCurl 向下翻頁效果
cameraIrisHollowOpen 攝像頭打開效果
cameraIrisHollowClose 攝像頭關閉效果
  • subtype動畫子類型
屬性 說明
kCATransitionFromRight 從右
kCATransitionFromLeft 從左
kCATransitionFromTop 從頂部
kCATransitionFromBottom 從底部

在瞭解上面兩個屬性後,對應轉場動畫,就差很少了
部分代碼以下

- (void)transition:(BOOL)next
{
    CATransition *transition = [CATransition animation];
    transition.type = @"cube";
    if (next)
    {
        transition.subtype = kCATransitionFromLeft;
    }
    else
    {
        transition.subtype = kCATransitionFromRight;
    }
    transition.duration = 1.0;
    
    _imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld.jpg",(long)_currentIndex]];
    [_imageView.layer addAnimation:transition forKey:@"transitionAnimation"];
}

效果以下

transanimation.gif

彈簧動畫

彈簧動畫是在iOS 9後纔出現的,在這以前,咱們能夠經過下面的方法來實現

[UIView animateWithDuration:5.0 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveLinear animations:^{

    } completion:nil];

iOS 9後蘋果公開了這一API,咱們先對其中的屬性進行分析,由於代碼中有註釋,因此就直接貼一部分代碼

//質量,影響圖層運動時的彈簧慣性,質量越大,彈簧拉伸和壓縮的幅度越大
        positionAnimation.mass = 0.1;
        //阻尼係數,阻止彈簧伸縮的係數,阻尼係數越大,中止越快
        positionAnimation.damping = 2;
        //剛度係數(勁度係數/彈性係數),剛度係數越大,形變產生的力就越大,運動越快
        positionAnimation.stiffness = 50;
        //初始速率,動畫視圖的初始速度大小
        //速率爲正數時,速度方向與運動方向一致,速率爲負數時,速度方向與運動方向相反
        positionAnimation.initialVelocity = -10;

關於彈簧動畫,我也寫了一個例子,效果以下

springanimation.gif

項目文件截圖:

寫在最後

關於核心動畫,差很少就簡單的介紹這麼點,若有什麼不對的還望各位多多指教,不甚感激。iOS 核心動畫 Core Animation淺談

代碼地址以下:
http://www.demodashi.com/demo/11603.html

注:本文著做權歸做者,由demo大師代發,拒絕轉載,轉載須要做者受權

相關文章
相關標籤/搜索