CAAnimation 系列動畫

CAAnimation繼承關係

    引用官方文檔:html

Core Animation provides high frame rates and smooth animations without burdening the CPU and slowing down your app. Most of the work required to draw each frame of an animation is done for you. You configure animation parameters such as the start and end points, and Core Animation does the rest, handing off most of the work to dedicated graphics hardware, to accelerate rendering. For more details, see Core Animation Programming Guide.git

    Core Animation提供了高幀率和流暢的動畫,而不會加劇CPU負擔,也不會減慢應用程序的速度。你能夠配置動畫參數,如起始點和結束點,Core animation完成其他部分,將大部分工做交給專用的圖形硬件,以加速渲染。github

CAAnimation類圖.jpg

    對於CAAnimation,是核心動畫基礎類,不直接使用,通常用它的子類。CAAnimation有三個子類CAPropertyAnimation、CATransition、CAAnimationGroup。第二個CATransition是轉場動畫,第三個CAAnimationGroup是動畫組。第一個CAPropertyAnimation又分爲兩個子類CABasicAnimation、CAKeyframeAnimationCAKeyframeAnimation是關鍵幀動畫。CABasicAnimation下面還有個子類CASpringAnimation是彈簧動畫。spring

    CAPropertyAnimation經過animationWithKeyPath來建立動畫,能夠看看有哪些屬性能夠建立動畫。詳見官方文檔數組

anchorPoint
backgroundColor
backgroundFilters
borderColor
borderWidth
bounds
compositingFilter
contents
contentsRect
cornerRadius
doubleSided
filters
frame
hidden
mask
masksToBounds
opacity
position
shadowColor
shadowOffset
shadowOpacity
shadowPath
shadowRadius
sublayers
sublayerTransform
transform
zPosition
複製代碼

CAKeyframeAnimation 關鍵幀動畫

    可使用繼承的animationWithKeyPath:方法建立一個CAKeyframeAnimation對象,並指定要在層上動畫的屬性的關鍵路徑。而後能夠指定用於控制時間和動畫行爲的關鍵幀值。對於大多數動畫類型,可使用值和keyTimes屬性指定關鍵幀值。在動畫期間,Core animation經過在您提供的值之間插入來生成中間值。當動畫一個座標點(例如layer的位置)的值時,你能夠指定該點的路徑,而不是單獨的值。動畫的節奏由你提供的時間信息控制。bash

重要屬性

屬性 描述
values 用來存放關鍵幀的數組
path 基於點的屬性的路徑。
keyTimes 對應關鍵幀段的時間點的NSNumber數組
timingFunctions 關鍵幀動畫節奏的數組,好比快進慢出、慢進快出等
calculationMode 肯定沿路徑動畫的對象是否旋轉以匹配路徑切線
tensionValues 定義曲線的緊密性的NSNumber數組
continuityValues 定義時間曲線銳角的NSNumber數組
biasValues 定義曲線相對於控制點的位置的NSNumber數組
Rotation Mode Values rotationMode屬性使用這些常量
Value calculation modes calculationMode屬性使用這些常量

效果代碼

#pragma mark - 指定keyPath爲position,經過Values來建立關鍵幀動畫
- (void)CAKeyframeAnimationWithValues
{
    CGFloat margin = 50.f;

    CAKeyframeAnimation * animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position";
    NSValue * value0 = [NSValue valueWithCGPoint:CGPointMake(margin, margin)];
    NSValue * value1 = [NSValue valueWithCGPoint:CGPointMake(margin, SCREENHEIGHT - margin)];
    NSValue * value2 = [NSValue valueWithCGPoint:CGPointMake(SCREENWIDTH - margin, SCREENHEIGHT - margin)];
    NSValue * value3 = [NSValue valueWithCGPoint:CGPointMake(SCREENWIDTH - margin, margin)];
    NSValue * value4 = [NSValue valueWithCGPoint:CGPointMake(margin, margin)];
    animation.values = @[value0,value1,value2,value3,value4];

    //當咱們動畫完成時,若是但願動畫就自動移除的話,咱們能夠設置此屬性爲YES,默認值爲YES
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = NO;
    animation.duration = 4;
    animation.repeatCount = MAXFLOAT;
    //快入快出
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [self.pointView.layer addAnimation:animation forKey:@"position.values"];
}

#pragma mark - 指定keyPath爲position,經過path路徑來建立關鍵幀動畫
- (void)CAKeyframeAnimationWithPath
{
    CGFloat margin = 50.f;

    CAKeyframeAnimation * animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position";

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, CGRectMake(margin, margin, SCREENWIDTH - margin * 2, SCREENHEIGHT - margin * 2));
    animation.path = path;
    CGPathRelease(path);

    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = NO;
    animation.duration = 4;
    animation.repeatCount = MAXFLOAT;
    NSMutableArray * timingFunctionArray = [NSMutableArray new];
    for (NSInteger i = 0 ; i < 5 ; i ++)
    {
        //每一段都是快出效果
        CAMediaTimingFunction * timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
        [timingFunctionArray addObject:timingFunction];
    }
    
    animation.timingFunctions = timingFunctionArray;
    [self.pointView.layer addAnimation:animation forKey:@"position.path"];
}

複製代碼

效果圖

CAKeyframeAnimation.gif

    須要注意的是removedOnCompletion設置爲NO的時候,不須要layer的時候要根據key手動移除動畫。app

[self.pointView.layer removeAnimationForKey:@"position.values"];
[self.pointView.layer removeAnimationForKey:@"position.path"];
複製代碼

CATransition 轉場動畫

    CATransition的父類是CAAnimation,和CAPropertyAnimationCAAnimationGroup同級。CATransition是用來視圖的轉場動畫。dom

You can transition between a layer's states by creating and adding a CATransition object to it. The default transition is a cross fade, but you can specify different effects from a set of predefined transitions.ide

重要屬性

屬性 描述
startProgress 整個變形接收的起點
endProgress 整個變形接收的終點
type 指定轉換類型
subtype 轉換方向的子類型
filter 提供轉換的圖像過濾器對象
Common Transition Types 指定能夠與type屬性一塊兒使用的轉換類型的常量
Common Transition Subtypes 指定能夠與subtype屬性一塊兒使用的轉換類型的常量

效果代碼

    其中typesubtype有官方指定的類型動畫

/* Common transition types. */

CA_EXTERN NSString * const kCATransitionFade
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionMoveIn
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionPush
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionReveal
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);

/* Common transition subtypes. */

CA_EXTERN NSString * const kCATransitionFromRight
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionFromLeft
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionFromTop
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionFromBottom
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
複製代碼

    還有幾種效果是私有API,在官方文檔中找不到,慎用

Cube,                     //立體
SuckEffect,               //吮吸
OglFlip,                  //翻轉
RippleEffect,             //波紋
PageCurl,                 //翻頁
PageUnCurl,               //反翻頁
CameraIrisHollowOpen,     //開鏡頭
CameraIrisHollowClose,    //關鏡頭
複製代碼

    這裏寫了一個例子,有12種type轉場效果和4種subtype轉場方向,用枚舉來封裝一下

typedef NS_ENUM(NSInteger,CATransactionType) {
    CATransactionType_Fade = 0,                 //默認
    CATransactionType_MoveIn,                   //覆蓋
    CATransactionType_Push,                     //推入
    CATransactionType_Reveal,                   //揭開

    CATransactionType_Cube,                     //立體
    CATransactionType_SuckEffect,               //吮吸
    CATransactionType_OglFlip,                  //翻轉
    CATransactionType_RippleEffect,             //波紋
    CATransactionType_PageCurl,                 //翻頁
    CATransactionType_PageUnCurl,               //反翻頁
    CATransactionType_CameraIrisHollowOpen,     //開鏡頭
    CATransactionType_CameraIrisHollowClose,    //關鏡頭
};

- (void)CATransitionWithType:(NSString *)type WithSubtype:(NSString *)subtype
{
    CATransition * animation = [CATransition animation];
    animation.duration = 2.f;
    animation.type = type;
    animation.subtype = subtype;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [self.view.layer addAnimation:animation forKey:nil];
}

- (void)btnClick:(UIButton *)sender
{
    UIButton * lastBtn;
    NSInteger index = sender.tag - 100;
    if (index > 11)
    {
        lastBtn = (UIButton *)[self.view viewWithTag:_subtype + 100];
        [lastBtn setBackgroundImage:[self createImageWithColor:self.subtypeNormalColor] forState:UIControlStateNormal];
        [sender setBackgroundImage:[self createImageWithColor:self.subtypeSelectedColor] forState:UIControlStateNormal];
        _subtype = index;
    }
    else
    {
        lastBtn = (UIButton *)[self.view viewWithTag:_transactionType + 100];
        [lastBtn setBackgroundImage:[self createImageWithColor:self.typeNormalColor] forState:UIControlStateNormal];
        [sender setBackgroundImage:[self createImageWithColor:self.typeSelectedColor] forState:UIControlStateNormal];
        _transactionType = index;
    }

    NSString * subtypeString ;

    switch (_subtype % 4) {
        case 0:
            subtypeString = kCATransitionFromTop;
            break;
        case 1:
            subtypeString = kCATransitionFromBottom;
            break;
        case 2:
            subtypeString = kCATransitionFromLeft;
            break;
        case 3:
            subtypeString = kCATransitionFromRight;
            break;

        default:
            break;
    }



    switch (_transactionType) {
        case CATransactionType_Fade:
            [self CATransitionWithType:kCATransitionFade WithSubtype:subtypeString];
            break;
        case CATransactionType_MoveIn:
            [self CATransitionWithType:kCATransitionMoveIn WithSubtype:subtypeString];
            break;
        case CATransactionType_Push:
            [self CATransitionWithType:kCATransitionPush WithSubtype:subtypeString];
            break;
        case CATransactionType_Reveal:
            [self CATransitionWithType:kCATransitionReveal WithSubtype:subtypeString];
            break;

        case CATransactionType_Cube:
            [self CATransitionWithType:@"cube" WithSubtype:subtypeString];
            break;
        case CATransactionType_SuckEffect:
            [self CATransitionWithType:@"suckEffect" WithSubtype:subtypeString];
            break;
        case CATransactionType_OglFlip:
            [self CATransitionWithType:@"oglFlip" WithSubtype:subtypeString];
            break;
        case CATransactionType_RippleEffect:
            [self CATransitionWithType:@"rippleEffect" WithSubtype:subtypeString];
            break;
        case CATransactionType_PageCurl:
            [self CATransitionWithType:@"pageCurl" WithSubtype:subtypeString];
            break;
        case CATransactionType_PageUnCurl:
            [self CATransitionWithType:@"pageUnCurl" WithSubtype:subtypeString];
            break;
        case CATransactionType_CameraIrisHollowOpen:
            [self CATransitionWithType:@"cameraIrisHollowOpen" WithSubtype:subtypeString];
            break;
        case CATransactionType_CameraIrisHollowClose:
            [self CATransitionWithType:@"cameraIrisHollowClose" WithSubtype:subtypeString];
            break;


        default:
            break;
    }

    static NSInteger i = 0;
    self.bgView.image = i % 2 ? [UIImage imageNamed:@"拉姆.jpeg"] :[UIImage imageNamed:@"蕾姆.jpeg"];
    i ++;
}
複製代碼

效果圖

CATransition1.gif
CATransition2.gif


CAAnimationGroup 動畫組

    分組動畫在CAAnimationGroup實例指定的時間中運行。分組動畫的持續時間不會被縮放到他們的CAAnimationGroup的持續時間。相反,動畫被剪切到動畫組的持續時間。例如,在一個動畫組中分組的10秒動畫,持續時間爲5秒,只顯示動畫的前5秒。

效果代碼

#pragma mark - 一個紅包雨的例子
- (void)showRain
{
    UIImageView * imageV = [UIImageView new];
    imageV.image = [UIImage imageNamed:@"page"];
    imageV.frame = CGRectMake(0, 0, 50 , 50 );

    CALayer * layer = [CALayer layer];
    layer.bounds = imageV.frame;
    layer.contents = (id)imageV.image.CGImage;
    layer.anchorPoint = CGPointMake(0, 0);
    layer.position = CGPointMake(0, 0);
    [self.view.layer addSublayer:layer];


    [self addAnimationWithLayer:layer];
}

- (void)addAnimationWithLayer:(CALayer *)layer
{
    int height = [UIScreen mainScreen].bounds.size.height;
    int width = [UIScreen mainScreen].bounds.size.height;

    CAKeyframeAnimation * moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    NSValue * A = [NSValue valueWithCGPoint:CGPointMake(arc4random() % width, 0)];
    NSValue * B = [NSValue valueWithCGPoint:CGPointMake(arc4random() % width, height + 100)];
    moveAnimation.values = @[A,B];
    moveAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

    CAKeyframeAnimation * tranAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    CATransform3D r0 = CATransform3DMakeRotation(M_PI/180 * (arc4random() % 360 ) , 0, 0, -1);
    CATransform3D r1 = CATransform3DMakeRotation(M_PI/180 * (arc4random() % 360 ) , 0, 0, -1);
    tranAnimation.values = @[[NSValue valueWithCATransform3D:r0],[NSValue valueWithCATransform3D:r1]];
    tranAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    CAAnimationGroup * group = [[CAAnimationGroup alloc] init];
    group.duration = arc4random() % 200 / 100.0 + 3.5;
    group.fillMode = kCAFillModeForwards;
    group.removedOnCompletion = NO;
    group.animations = @[moveAnimation,tranAnimation];
    [layer addAnimation:group forKey:nil];
}

複製代碼

效果圖

CAAnimationGroup.gif


CASpringAnimation 彈簧動畫

    CASpringAnimation的父類是CABasicAnimation, CABasicAnimation能夠當作是隻有頭尾有值的關鍵幀動畫。

You would typically use a spring animation to animate a layer's position so that it appears to be pulled towards a target by a spring. The further the layer is from the target, the greater the acceleration towards it is. CASpringAnimation allows control over physically based attributes such as the spring's damping and stiffness.

    CASpringAnimation是基於物理的屬性控制,好比彈簧的阻尼和剛度。

重要屬性

屬性 描述
damping 定義彈簧運動如何受到阻尼的影響
initialVelocity 初速度
mass 鏈接到彈簧末端的物體的質量
settlingDuration 預估靜止時間
stiffness 彈簧剛度係數

效果代碼

- (void)btnClick:(UIButton *)sender
{
    //frame屬性不可動畫化 只能經過 bounds 和 position完成
    CASpringAnimation * animation = [CASpringAnimation animationWithKeyPath:@"bounds"];

    //質量,影響圖層運動時的彈簧慣性,質量越大,彈簧拉伸和壓縮的幅度越大
    animation.mass = self.massSlider.value;

    //剛度係數(勁度係數/彈性係數),剛度係數越大,形變產生的力就越大,運動越快
    animation.stiffness = self.stiffnessSlider.value;

    //阻尼係數,阻止彈簧伸縮的係數,阻尼係數越大,中止越快
    animation.damping = self.dampingSlider.value;

    //初始速率,動畫視圖的初始速度大小;速率爲正數時,速度方向與運動方向一致,速率爲負數時,速度方向與運動方向相反
    animation.initialVelocity = self.velocitySlider.value;

    animation.duration = 3.f;
    animation.fromValue =  [NSValue valueWithCGRect:CGRectMake(0, 0, 80, 100)];
    animation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 80, 240)];
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [self.baseView.layer addAnimation:animation forKey:nil];

    CASpringAnimation * animation1 = [CASpringAnimation animationWithKeyPath:@"position"];
    animation1.duration = 3.f;
    animation1.fromValue = [NSValue valueWithCGPoint:CGPointMake(SCREENWIDTH / 2 , 250)];
    animation1.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREENWIDTH / 2 , 250 - 70)];
    animation1.removedOnCompletion = NO;
    animation1.fillMode = kCAFillModeForwards;
    [self.baseView.layer addAnimation:animation1 forKey:nil];
}
複製代碼

效果圖

CASpringAnimation.gif


UIView的彈簧動畫

另外在看看cell上用UIView Block彈簧動畫的特效

效果代碼

+ (void)animateWithDuration:(NSTimeInterval)duration
                      delay:(NSTimeInterval)delay
     usingSpringWithDamping:(CGFloat)dampingRatio
      initialSpringVelocity:(CGFloat)velocity
                    options:(UIViewAnimationOptions)options
                 animations:(void (^)(void))animations
                 completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
複製代碼
- (void)cellAnimation
{
    [self.springTableView reloadData];

    NSArray * cellArrays = self.springTableView.visibleCells;
    CGFloat height = self.springTableView.bounds.size.height;

    for (UITableView * cell in cellArrays)
    {
        cell.transform = CGAffineTransformMakeTranslation(-SCREENWIDTH, height);
    }

    for (NSInteger i = 0 ; i < cellArrays.count ; i ++ )
    {
        UITableViewCell * cell = (UITableViewCell *)cellArrays[i];
        [UIView animateWithDuration:1.5
                              delay:0.05 * i
             usingSpringWithDamping:0.8
              initialSpringVelocity:0
                            options:0 animations:^{
                    cell.transform = CGAffineTransformMakeTranslation(0, 0);
            } completion:nil];
    }
}
複製代碼

效果圖

CellSpringAnimation.gif

源碼: CAAnimation

相關文章
相關標籤/搜索