iOS動畫-通篇詳解

原創(chuàng)內(nèi)容,轉(zhuǎn)載請注明出處:

http://www.reibang.com/p/3f48fabaca19

前言

上次總結(jié)了多線程的用法,這次再復(fù)習下iOS動畫的東西.這次依然先是以api為主,因為好多人還是api好多的東西還不會用.然后中間穿插些例子,例子和代碼文章中都會有.因為篇幅比較長,先列一下大綱.

動畫的繼承結(jié)構(gòu)


CAAnimation{
     CAPropertyAnimation{
            CABasicAnimation{
                    CASpringAnimation
            }
            CAKeyframeAnimation
     }
     CATransition   
     CAAnimationGroup
}

CAAnimation(動畫根類,不可以直接使用)



CAAnimation-屬性(復(fù)雜點的屬性,下面會有詳細解釋)

//動畫的代理回調(diào),下面會有
@property(nullable, strong) id delegate;
//動畫執(zhí)行完以后是否移除動畫,默認YES
@property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;
//動畫的動作規(guī)則,包含以下值
//kCAMediaTimingFunctionLinear 勻速
//kCAMediaTimingFunctionEaseIn 慢進快出
//kCAMediaTimingFunctionEaseOut 快進慢出
//kCAMediaTimingFunctionEaseInEaseOut 慢進慢出 中間加速
//kCAMediaTimingFunctionDefault 默認
@property(nullable, strong) CAMediaTimingFunction *timingFunction;

以上屬性的詳解:

  • delegate:動畫執(zhí)行的代理,在動畫開始前設(shè)定,不用顯式的寫在代碼里,它包含兩個方法:
    動畫開始回調(diào)
    - (void)animationDidStart:(CAAnimation *)anim;
    動畫結(jié)束回調(diào)
    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
  • removedOnCompletion:動畫完成后是否移除動畫.默認為YES.此屬性為YES時, fillMode不可用,具體為什么不可用,可以自己結(jié)合兩個屬性分析一下,這里不再贅述.
  • timingFunction 設(shè)置動畫速度曲線,默認值上面已經(jīng)給出.下面說它的幾個方法:
    這兩個方法是一樣的.如果我們對系統(tǒng)自帶的速度函數(shù)不滿意,可以通過這兩個函數(shù)創(chuàng)建一個自己喜歡的速度曲線函數(shù),具體用法可以參考這篇文章CAMediaTimingFunction的使用
    + (instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
    - (instancetype)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
    獲取曲線函數(shù)的緩沖點,具體用法可以參考這篇文章:iOS-核心動畫高級編程/10-緩沖
    - (void)getControlPointAtIndex:(size_t)idx values:(float[2])ptr;

CAAnimation <CAMediaTiming>協(xié)議的屬性

//開始時間.這個屬性比較復(fù)雜,傻瓜用法為:CACurrentMediaTime() + x,
//其中x為延遲時間.如果設(shè)置 beginTime = CACurrentMediaTime() + 1.0,產(chǎn)生的效果為延遲一秒執(zhí)行動畫,下面詳解原理
@property CFTimeInterval beginTime;
//動畫執(zhí)行時間,此屬性和speed有關(guān)系speed默認為1.0,如果speed設(shè)置為2.0,那么動畫執(zhí)行時間則為duration*(1.0/2.0).
@property CFTimeInterval duration;
//動畫執(zhí)行速度,它duration的關(guān)系參考上面解釋
@property float speed;
//動畫的時間延遲,這個屬性比較復(fù)雜,下面詳解
@property CFTimeInterval timeOffset;
//重復(fù)執(zhí)行次數(shù)
@property float repeatCount;
//重復(fù)執(zhí)行時間,此屬性優(yōu)先級大于repeatCount.也就是說如果repeatDuration設(shè)置為1秒重復(fù)10次,那么它會在1秒內(nèi)執(zhí)行完動畫.
@property CFTimeInterval repeatDuration;
//是否自動翻轉(zhuǎn)動畫,默認NO.如果設(shè)置YES,那么整個動畫的執(zhí)行效果為A->B->A.
@property BOOL autoreverses;
//動畫的填充方式,默認為: kCAFillModeRemoved,包含以下值
//kCAFillModeForwards//動畫結(jié)束后回到準備狀態(tài)
//kCAFillModeBackwards//動畫結(jié)束后保持最后狀態(tài)
//kCAFillModeBoth//動畫結(jié)束后回到準備狀態(tài),并保持最后狀態(tài)
//kCAFillModeRemoved//執(zhí)行完成移除動畫
@property(copy) NSString *fillMode;

以上屬性的詳解:

  • beginTime:剛才上面簡單解釋了下這個屬性的用法:CACurrentMediaTime()+ x 會使動畫延遲執(zhí)行x秒.不知道到這里有沒有人想過如果-x會出現(xiàn)怎么樣效果?假設(shè)我們有執(zhí)行一個3秒的動畫,然后設(shè)置beginTime = CACurrentMediaTime()- 1.5那么執(zhí)行動畫你會發(fā)現(xiàn)動畫只會執(zhí)行后半段,也就是只執(zhí)行后面的3-1.5s的動畫.為什么會這樣?其實動畫都有一個timeline(時間線)的概念.動畫開始執(zhí)行都是基于這個時間線的絕對時間,這個時間和它的父類有關(guān)(系統(tǒng)的屬性注釋可以看到).默認的CALayer的beginTime為零,如果這個值為零的話,系統(tǒng)會把它設(shè)置為CACurrentMediaTime(),那么這個時間就是正常執(zhí)行動畫的時間:立即執(zhí)行.所以如果你設(shè)置beginTime=CACurrentMediaTime()+x;它會把它的執(zhí)行時間線推遲x秒,也就是晚執(zhí)行x秒,如果你beginTime=CACurrentMediaTime()-x;那它開始的時候會從你動畫對應(yīng)的絕對時間開始執(zhí)行.
  • timeOffset:時間偏移量,默認為0;既然它是時間偏移量,那么它即和動畫時間相關(guān).這么解釋:假設(shè)我們設(shè)置一個動畫時間為5s,動畫執(zhí)行的過程為1->2->3->4->5,這時候如果你設(shè)置timeOffset = 2s那么它的執(zhí)行過程就會變成3->4->5->1->2如果你設(shè)置timeOffset = 4s那么它的執(zhí)行過程就會變成5->1->2->3->4,這么說應(yīng)該很明白了吧?

CAPropertyAnimation屬性動畫,抽象類,不能直接使用

CAPropertyAnimation的屬性

//需要動畫的屬性值
@property(nullable, copy) NSString *keyPath;
//屬性動畫是否以當前動畫效果為基礎(chǔ),默認為NO
@property(getter=isAdditive) BOOL additive;
//指定動畫是否為累加效果,默認為NO
@property(getter=isCumulative) BOOL cumulative;
//此屬性相當于CALayer中的transform屬性,下面會詳解
@property(nullable, strong) CAValueFunction *valueFunction;

以上屬性的詳解:

CAPropertyAnimation是屬性動畫.顧名思義也就是針對屬性才可以做的動畫.那它可以對誰的屬性可以做動畫?是CALayer的屬性,比如:bounds,position等.那么問題來了,我們改變CALayer的position可以直接設(shè)置[CAPropertyAnimation animationWithKeyPath:@"position"]如果我們設(shè)置它的transform(CATransform3D)呢?CATransform3D是一個矩陣,如果我們想為它做動畫怎么辦?下面這個屬性就是用來解決這個問題的.

  • valueFunction:我們來看它可以設(shè)置的值:
    kCAValueFunctionRotateX
    kCAValueFunctionRotateY
    kCAValueFunctionRotateZ
    kCAValueFunctionScale
    kCAValueFunctionScaleX
    kCAValueFunctionScaleY
    kCAValueFunctionScaleZ
    kCAValueFunctionTranslate
    kCAValueFunctionTranslateX
    kCAValueFunctionTranslateY
    kCAValueFunctionTranslateZ
    說到這里大家應(yīng)該都知道該怎么用了吧~.

CAPropertyAnimation的方法

//通過key創(chuàng)建一個CAPropertyAnimation對象
+ (instancetype)animationWithKeyPath:(nullable NSString *)path;

下面我們來看一下可以設(shè)置屬性動畫的屬性歸總:

CATransform3D{
    rotation旋轉(zhuǎn)
    transform.rotation.x
    transform.rotation.y
    transform.rotation.z

    scale縮放
    transform.scale.x
    transform.scale.y
    transform.scale.z

    translation平移
    transform.translation.x
    transform.translation.y
    transform.translation.z
}

CGPoint{
    position
    position.x
    position.y
}

CGRect{
    bounds
    bounds.size
    bounds.size.width
    bounds.size.height

    bounds.origin
    bounds.origin.x
    bounds.origin.y
}

property{
    opacity
    backgroundColor
    cornerRadius
    borderWidth
    contents
    
    Shadow{
        shadowColor
        shadowOffset
        shadowOpacity
        shadowRadius
    }
}

總結(jié): CAAnimation是基類, CAPropertyAnimation是抽象類,兩者都不可以直接使用, 那我們只有使用它的子類了.

CABasicAnimation基本動畫

CABasicAnimation的屬性

//開始值
@property(nullable, strong) id fromValue;
//結(jié)束值
@property(nullable, strong) id toValue;
//結(jié)束值
@property(nullable, strong) id byValue;

這三個屬性之間的規(guī)則

  • fromValuetoValue不為空,動畫的效果會從fromValue的值變化到toValue.
  • fromValuebyValue都不為空,動畫的效果將會從fromValue變化到fromValue+byValue
  • toValuebyValue都不為空,動畫的效果將會從toValue-byValue變化到toValue
  • 只有fromValue的值不為空,動畫的效果將會從fromValue的值變化到當前的狀態(tài).
  • 只有toValue的值不為空,動畫的效果將會從當前狀態(tài)的值變化到toValue的值.
    只有byValue的值不為空,動畫的效果將會從當前的值變化到(當前狀態(tài)的值+byValue)的值.

CABasicAnimation看起來不太復(fù)雜,但實際只用這個就足以可以做很多種動畫了,下面簡單用一下,先看效果:

CABasicAnimation.gif

然后再看下實現(xiàn)代碼:


#import "ViewController.h"
#import "TFEasyCoder.h"
@interface ViewController ()

@property (nonatomic,strong)UIView *demoView;


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
 
    kdeclare_weakself;
    NSArray *titles = @[@"淡入淡出",@"縮放",@"旋轉(zhuǎn)",@"平移"];
    for (unsigned int i = 0; i < titles.count; i++) {
        
        [UIButton easyCoder:^(UIButton *ins) {
            [weakSelf.view addSubview:ins];
            ins.backgroundColor = [UIColor brownColor];
            ins.tag = i;
            ins.frame = CGRectMake(10, 50 + 80 * i, 100, 60);
            [ins setTitle:titles[i] forState:UIControlStateNormal];
            [ins addTarget:self action:@selector(animationBegin:) forControlEvents:UIControlEventTouchUpInside];
        }];
    }
    
    
    [UIView easyCoder:^(UIView *ins) {
        
        ins.frame = CGRectMake(0, 0, 100, 100);
        ins.backgroundColor = [UIColor redColor];
        ins.center = self.view.center;
        
        weakSelf.demoView = ins;
        [weakSelf.view addSubview:weakSelf.demoView];
    }];
    

    
}

-(void)animationBegin:(UIButton *)btn{
    CABasicAnimation *animation = nil;
    switch (btn.tag) {
        case 0:{
            //淡如淡出
            animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
            [animation setFromValue:@1.0];
            [animation setToValue:@0.1];
        }break;
        case 1:{
            //縮放
            animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
            [animation setFromValue:@1.0];//設(shè)置起始值
            [animation setToValue:@0.1];//設(shè)置目標值
        }break;
        case 2:{
            //旋轉(zhuǎn)
            animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
            //setFromValue不設(shè)置,默認以當前狀態(tài)為準
            [animation setToValue:@(M_PI)];
        }break;
        case 3:{
            //平移
            animation = [CABasicAnimation animationWithKeyPath:@"position"];
            //setFromValue不設(shè)置,默認以當前狀態(tài)為準
            [animation setToValue:[NSValue valueWithCGPoint:CGPointMake(self.view.center.x, self.view.center.y + 200)]];
        }break;
        default:break;
    }
    [animation setDelegate:self];//代理回調(diào)
    [animation setDuration:0.25];//設(shè)置動畫時間步脓,單次動畫時間
    [animation setRemovedOnCompletion:NO];//默認為YES,設(shè)置為NO時setFillMode有效
    /**
     *設(shè)置時間函數(shù)CAMediaTimingFunction
     *kCAMediaTimingFunctionLinear 勻速
     *kCAMediaTimingFunctionEaseIn 開始速度慢掸掏,后來速度快
     *kCAMediaTimingFunctionEaseOut 開始速度快 后來速度慢
     *kCAMediaTimingFunctionEaseInEaseOut = kCAMediaTimingFunctionDefault 中間速度快,兩頭速度慢
     */
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    //設(shè)置自動翻轉(zhuǎn)
    //設(shè)置自動翻轉(zhuǎn)以后單次動畫時間不變,總動畫時間增加一倍,它會讓你前半部分的動畫以相反的方式動畫過來
    //比如說你設(shè)置執(zhí)行一次動畫,從a到b時間為1秒,設(shè)置自動翻轉(zhuǎn)以后動畫的執(zhí)行方式為,先從a到b執(zhí)行一秒海铆,然后從b到a再執(zhí)行一下動畫結(jié)束
    [animation setAutoreverses:YES];
    //kCAFillModeForwards//動畫結(jié)束后回到準備狀態(tài)
    //kCAFillModeBackwards//動畫結(jié)束后保持最后狀態(tài)
    //kCAFillModeBoth//動畫結(jié)束后回到準備狀態(tài),并保持最后狀態(tài)
    //kCAFillModeRemoved//執(zhí)行完成移除動畫
    [animation setFillMode:kCAFillModeBoth];
    //將動畫添加到layer,添加到圖層開始執(zhí)行動畫,
    //注意:key值的設(shè)置與否會影響動畫的效果
    //如果不設(shè)置key值每次執(zhí)行都會創(chuàng)建一個動畫挣惰,然后創(chuàng)建的動畫會疊加在圖層上
    //如果設(shè)置key值卧斟,系統(tǒng)執(zhí)行這個動畫時會先檢查這個動畫有沒有被創(chuàng)建,如果沒有的話就創(chuàng)建一個通熄,如果有的話就重新從頭開始執(zhí)行這個動畫
    //你可以通過key值獲取或者刪除一個動畫:
    //[self.demoView.layer animationForKey:@""];
    //[self.demoView.layer removeAnimationForKey:@""]
    [self.demoView.layer addAnimation:animation forKey:@"baseanimation"];
}

/**
 *  動畫開始和動畫結(jié)束時 self.demoView.center 是一直不變的唆涝,說明動畫并沒有改變視圖本身的位置
 */
- (void)animationDidStart:(CAAnimation *)anim{
    NSLog(@"動畫開始------:%@",    NSStringFromCGPoint(self.demoView.center));
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    NSLog(@"動畫結(jié)束------:%@",    NSStringFromCGPoint(self.demoView.center));
}

以上效果和代碼還有注釋都解釋的很詳細了,然后源碼在這里:demo-基本動畫

CASpringAnimation彈性動畫

CASpringAnimation的屬性(iOS9新加)

//理解下面的屬性的時候可以結(jié)合現(xiàn)實物理現(xiàn)象,比如把它想象成一個彈簧上掛著一個金屬小球
//質(zhì)量,振幅和質(zhì)量成反比
@property CGFloat mass;
//剛度系數(shù)(勁度系數(shù)/彈性系數(shù)),剛度系數(shù)越大,形變產(chǎn)生的力就越大,運動越快
@property CGFloat stiffness;
//阻尼系數(shù),阻止彈簧伸縮的系數(shù),阻尼系數(shù)越大,停止越快,可以認為它是阻力系數(shù)
@property CGFloat damping;
//初始速率,動畫視圖的初始速度大小速率為正數(shù)時,速度方向與運動方向一致,速率為負數(shù)時,速度方向與運動方向相反.
@property CGFloat initialVelocity;
//結(jié)算時間,只讀.返回彈簧動畫到停止時的估算時間,根據(jù)當前的動畫參數(shù)估算通常彈簧動畫的時間使用結(jié)算時間比較準確
@property(readonly) CFTimeInterval settlingDuration;

下面我們寫一個demo看看效果:

spring彈性動畫.gif

以上gif的代碼為:

CASpringAnimation *spring = [CASpringAnimation animationWithKeyPath:@"position.y"];
spring.damping = 5;
spring.stiffness = 100;
spring.mass = 1;
spring.initialVelocity = 0;
spring.duration = spring.settlingDuration;
spring.fromValue = @(self.demoView1.center.y);
spring.toValue = @(self.demoView1.center.y + (btn.selected?+200:-200));
spring.fillMode = kCAFillModeForwards;
[self.demoView1.layer addAnimation:spring forKey:nil];

CASpringAnimation效果不錯,但是很不幸只有iOS9+系統(tǒng)才能使用,這就很操蛋了.以前項目有過這樣的需求,然后就自己寫了一個類似的動畫,效果在下面:

自定義彈性動畫.gif

然后上面自定義彈性動畫的代碼在這里:


#import "UIView+ShakeAnimation.h"
#import <objc/runtime.h>
typedef void (^RunAnimationBlock)();
@interface UIView ()
@property (nonatomic,  copy)RunAnimationBlock block;
@end

@implementation UIView (ShakeAnimation)

-(void)startAnimationFromFrame:(CGRect)framef
                       toFrame:(CGRect)framet
                      duration:(CGFloat)duration
                    shakeTimes:(NSInteger)times
                stretchPercent:(CGFloat)stretchPercent
                    completion:(void (^)(BOOL finished))completion
{
    self.layer.masksToBounds = YES;
    
    __block CGFloat perTime = duration / times;
    __block CGFloat perx = (framet.origin.x - framef.origin.x) * stretchPercent / times;
    __block CGFloat pery = (framet.origin.y - framef.origin.y) * stretchPercent / times;
    __block CGFloat perw = (framet.size.width - framef.size.width) * stretchPercent / times;
    __block CGFloat perh = (framet.size.height - framef.size.height) * stretchPercent / times;
    
    __block UIView * tmpView = self;
    __block NSInteger tmpTimes = (NSInteger)times;
    __block NSInteger tmpsymbol = -1;

    __weak typeof(self) weakSelf = self;
    self.block = ^{
        
        [UIView animateWithDuration:perTime animations:^{
            
            CGFloat x = framet.origin.x + perx * tmpTimes;
            CGFloat y = framet.origin.y + pery * tmpTimes;
            CGFloat w = framet.size.width + perw * tmpTimes;
            CGFloat h = framet.size.height + perh * tmpTimes;
            CGRect rect = CGRectMake(x, y, w, h);
            
            tmpView.frame = rect;
        }completion:^(BOOL finished) {
            
            tmpTimes = tmpTimes + tmpsymbol;
            tmpTimes = - tmpTimes;
            tmpsymbol = - tmpsymbol;
            if (tmpTimes != 0) {
                weakSelf.block();
            }else{
                [UIView animateWithDuration:perTime animations:^{
                    tmpView.frame = framet;
                }completion:^(BOOL finished) {
                    completion(YES);
                }];
            }
        }];
    };
    
    self.block();
}
static char RunAnimationBlockKey;
-(RunAnimationBlock)block{
    return objc_getAssociatedObject(self, &RunAnimationBlockKey);
}
-(void)setBlock:(RunAnimationBlock)block{
    objc_setAssociatedObject(self, &RunAnimationBlockKey, block, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end

調(diào)用:


[self.demoView2 startAnimationFromFrame:CGRectMake(10, 300, 100, 100)
                                toFrame:CGRectMake(10, 300, 300, 100)
                               duration:0.5
                             shakeTimes:5
                         stretchPercent:0.3
                             completion:^(BOOL finished) {
                                 NSLog(@"======over======:%@",self.demoView1);
                             }];

上面兩個彈性動畫的代碼在這里:demo-彈性動畫

CAKeyframeAnimation關(guān)鍵幀動畫

CAKeyframeAnimation的屬性

//關(guān)鍵幀值數(shù)組,一組變化值
@property(nullable, copy) NSArray *values;
//關(guān)鍵幀幀路徑,優(yōu)先級比values大
@property(nullable) CGPathRef path;
//每一幀對應(yīng)的時間,時間可以控制速度.它和每一個幀相對應(yīng),取值為0.0-1.0,不設(shè)則每一幀時間相等.
@property(nullable, copy) NSArray<NSNumber *> *keyTimes;
//每一幀對應(yīng)的時間曲線函數(shù),也就是每一幀的運動節(jié)奏
@property(nullable, copy) NSArray<CAMediaTimingFunction *> *timingFunctions;
//動畫的計算模式,默認值: kCAAnimationLinear.有以下幾個值:
//kCAAnimationLinear//關(guān)鍵幀為座標點的時候,關(guān)鍵幀之間直接直線相連進行插值計算;
//kCAAnimationDiscrete//離散的,也就是沒有補間動畫
//kCAAnimationPaced//平均唇辨,keyTimes跟timeFunctions失效
//kCAAnimationCubic對關(guān)鍵幀為座標點的關(guān)鍵幀進行圓滑曲線相連后插值計算,對于曲線的形狀還可以通過tensionValues,continuityValues,biasValues來進行調(diào)整自定義,keyTimes跟timeFunctions失效
//kCAAnimationCubicPaced在kCAAnimationCubic的基礎(chǔ)上使得動畫運行變得均勻,就是系統(tǒng)時間內(nèi)運動的距離相同,,keyTimes跟timeFunctions失效
@property(copy) NSString *calculationMode;
//動畫的張力,當動畫為立方計算模式的時候此屬性提供了控制插值,因為每個關(guān)鍵幀都可能有張力所以連續(xù)性會有所偏差它的范圍為[-1,1].同樣是此作用
@property(nullable, copy) NSArray<NSNumber *> *tensionValues;
//動畫的連續(xù)性值
@property(nullable, copy) NSArray<NSNumber *> *continuityValues;
//動畫的偏斜率
@property(nullable, copy) NSArray<NSNumber *> *biasValues;
//動畫沿路徑旋轉(zhuǎn)方式,默認為nil.它有兩個值:
//kCAAnimationRotateAuto//自動旋轉(zhuǎn),
//kCAAnimationRotateAutoReverse//自動翻轉(zhuǎn)
@property(nullable, copy) NSString *rotationMode;

CAKeyframeAnimation可以做很豐富的效果,下面展示了幾種純CAKeyframeAnimation做的效果:

CAKeyframeAnimation.gif

以上效果的代碼都比較簡單,量也比較大,這里就不貼出來了,這里可以下載:demo-關(guān)鍵幀動畫

CAAnimationGroup動畫組

CAAnimationGroup的屬性

//只有一個屬性,數(shù)組中接受CAAnimation元素
@property(nullable, copy) NSArray<CAAnimation *> *animations;
  • 可以看到CAAnimationGroup只有一個屬性一個CAAnimation數(shù)組.而且它繼承于CAAnimation,它具有CAAnimation的特性,所以它的用法和CAAnimation是一樣的,不同的是他可以包含n個動畫,也就是說他可以接受很多個CAAnimation并且可以讓它們一起開始,這就造成了動畫效果的疊加,效果就是n個動畫同時進行.

來看一個簡單的效果:

CAAnimationGroup.gif

這個是動畫是,旋轉(zhuǎn),抖動,透明度一起作用在一起的效果,代碼在這里demo-動畫組

CATransition轉(zhuǎn)場動畫

//轉(zhuǎn)場類型,字符串類型參數(shù).系統(tǒng)提供了四中動畫形式:
//kCATransitionFade//逐漸消失
//kCATransitionMoveIn//移進來
//kCATransitionPush//推進來
//kCATransitionReveal//揭開
//另外,除了系統(tǒng)給的這幾種動畫效果,我們還可以使用系統(tǒng)私有的動畫效果:
//@"cube",//立方體翻轉(zhuǎn)效果
//@"oglFlip",//翻轉(zhuǎn)效果
//@"suckEffect",//收縮效果,動畫方向不可控
//@"rippleEffect",//水滴波紋效果,動畫方向不可控
//@"pageCurl",//向上翻頁效果
//@"pageUnCurl",//向下翻頁效果
//@"cameralIrisHollowOpen",//攝像頭打開效果,動畫方向不可控
//@"cameraIrisHollowClose",//攝像頭關(guān)閉效果,動畫方向不可控
@property(copy) NSString *type;
//轉(zhuǎn)場方向,系統(tǒng)一共提供四個方向:
//kCATransitionFromRight//從右開始
//kCATransitionFromLeft//從左開始
//kCATransitionFromTop//從上開始
//kCATransitionFromBottom//從下開始
@property(nullable, copy) NSString *subtype;
//開始進度,默認0.0.如果設(shè)置0.3,那么動畫將從動畫的0.3的部分開始
@property float startProgress;
//結(jié)束進度,默認1.0.如果設(shè)置0.6,那么動畫將從動畫的0.6部分以后就會結(jié)束
@property float endProgress;
//開始進度
@property(nullable, strong) id filter;

CATransition也是繼承CAAnimation,系統(tǒng)默認提供了12種動畫樣式,加上4個動畫方向,除了方向不可控的四種效果外,大概一共提供了36種動畫.

另外系統(tǒng)還給UIView添加了很多分類方法可以快速完成一些簡單的動畫,如下:

UIView(UIViewAnimation)

@interface UIView(UIViewAnimation)

+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;  // additional context info passed to will start/did stop selectors. begin/commit can be nested
//提交動畫
+ (void)commitAnimations;
//設(shè)置代理
+ (void)setAnimationDelegate:(nullable id)delegate;                          //設(shè)置動畫開始方法
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;                
//設(shè)置動畫結(jié)束方法
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;
//設(shè)置動畫時間:default = 0.2
+ (void)setAnimationDuration:(NSTimeInterval)duration;              
//設(shè)置動畫延遲開始時間:default = 0.0
+ (void)setAnimationDelay:(NSTimeInterval)delay;
//設(shè)置動畫延遲開始日期:default = now ([NSDate date])
+ (void)setAnimationStartDate:(NSDate *)startDate;                  
//設(shè)置動畫運動曲線:default =UIViewAnimationCurveEaseInOut
//UIViewAnimationCurveEaseInOut,//慢進慢出
//UIViewAnimationCurveEaseIn, //慢進快出
//UIViewAnimationCurveEaseOut,//快進慢出
//UIViewAnimationCurveLinear//勻速
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;              
//設(shè)置重復(fù)次數(shù): default = 0.0.  May be fractional
+ (void)setAnimationRepeatCount:(float)repeatCount;
//設(shè)置是否翻轉(zhuǎn)動畫: default = NO. used if repeat 
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
//設(shè)置動畫是否從當前狀態(tài)開始:default = NO
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;
//設(shè)置動畫類型
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache; 
//設(shè)置動畫是否有效
+ (void)setAnimationsEnabled:(BOOL)enabled;
//
+ (BOOL)areAnimationsEnabled;
//
+ (void)performWithoutAnimation:(void (^)(void))actionsWithoutAnimation
//
+ (NSTimeInterval)inheritedAnimationDuration 
@end

UIView(UIViewAnimationWithBlocks)


@interface UIView(UIViewAnimationWithBlocks)
//以下方法都大同小異,就不一一做注釋了
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion 
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;
+ (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
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion;
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

@end

UIView (UIViewKeyframeAnimations)

+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations

以上方法比較多,找值得說的簡單說一下吧:

//單視圖轉(zhuǎn)場動畫
+ (void)transitionWithView:(UIView *)view
                  duration:(NSTimeInterval)duration 
                   options:(UIViewAnimationOptions)options
                animations:(void (^ __nullable)(void))animations
                completion:(void (^ __nullable)(BOOL finished))completion
//雙視圖轉(zhuǎn)場動畫
+ (void)transitionFromView:(UIView *)fromView
                    toView:(UIView *)toView 
                  duration:(NSTimeInterval)duration 
                    options:(UIViewAnimationOptions)options
              completion:(void (^ __nullable)(BOOL finished))completion

這兩個都是轉(zhuǎn)場動畫,不同的是第一個是單視圖轉(zhuǎn)場,第二個是雙視圖轉(zhuǎn)場.不過需要注意的是:單視圖轉(zhuǎn)場動畫只能用作屬性動畫做不到的轉(zhuǎn)場效果,比如屬性動畫不能給UIImageview的image賦值操作做動畫效果等.

我們可以看到以上兩個方法中都有一個共同的參數(shù):
UIViewAnimationOptions

typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
    UIViewAnimationOptionLayoutSubviews            = 1 <<  0,
    UIViewAnimationOptionAllowUserInteraction      = 1 <<  1, // turn on user interaction while animating
    UIViewAnimationOptionBeginFromCurrentState     = 1 <<  2, // start all views from current value, not initial value
    UIViewAnimationOptionRepeat                    = 1 <<  3, // repeat animation indefinitely
    UIViewAnimationOptionAutoreverse               = 1 <<  4, // if repeat, run animation back and forth
    UIViewAnimationOptionOverrideInheritedDuration = 1 <<  5, // ignore nested duration
    UIViewAnimationOptionOverrideInheritedCurve    = 1 <<  6, // ignore nested curve
    UIViewAnimationOptionAllowAnimatedContent      = 1 <<  7, // animate contents (applies to transitions only)
    UIViewAnimationOptionShowHideTransitionViews   = 1 <<  8, // flip to/from hidden state instead of adding/removing
    UIViewAnimationOptionOverrideInheritedOptions  = 1 <<  9, // do not inherit any options or animation type
    
    UIViewAnimationOptionCurveEaseInOut            = 0 << 16, // default
    UIViewAnimationOptionCurveEaseIn               = 1 << 16,
    UIViewAnimationOptionCurveEaseOut              = 2 << 16,
    UIViewAnimationOptionCurveLinear               = 3 << 16,
    
    UIViewAnimationOptionTransitionNone            = 0 << 20, // default
    UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20,
    UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20,
    UIViewAnimationOptionTransitionCurlUp          = 3 << 20,
    UIViewAnimationOptionTransitionCurlDown        = 4 << 20,
    UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20,
    UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20,
    UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20,
} NS_ENUM_AVAILABLE_IOS(4_0);

可以看到系統(tǒng)給到的是一個位移枚舉,這就意味著這個枚舉可以多個值同時使用,但是怎么用呢?其實那些枚舉值可以分為三個部分.
我們分別看一下每個枚舉的意思:
第一部分:動畫效果

UIViewAnimationOptionTransitionNone//沒有效果
UIViewAnimationOptionTransitionFlipFromLeft//從左水平翻轉(zhuǎn)
UIViewAnimationOptionTransitionFlipFromRight//從右水平翻轉(zhuǎn)
UIViewAnimationOptionTransitionCurlUp//翻書上掀
UIViewAnimationOptionTransitionCurlDown//翻書下蓋UIViewAnimationOptionTransitionCrossDissolve//融合
UIViewAnimationOptionTransitionFlipFromTop//從上垂直翻轉(zhuǎn)                    UIViewAnimationOptionTransitionFlipFromBottom//從下垂直翻轉(zhuǎn)

第二部分:動畫運動曲線

//開始慢廊酣,加速到中間,然后減慢到結(jié)束
UIViewAnimationOptionCurveEaseInOut
//開始慢赏枚,加速到結(jié)束
UIViewAnimationOptionCurveEaseIn
//開始快亡驰,減速到結(jié)束
UIViewAnimationOptionCurveEaseOut
//線性運動
UIViewAnimationOptionCurveLinear

第三部分:其他

//默認,跟父類作為一個整體
UIViewAnimationOptionLayoutSubviews
//設(shè)置了這個饿幅,主線程可以接收點擊事件
UIViewAnimationOptionAllowUserInteraction
//從當前狀態(tài)開始動畫凡辱,父層動畫運動期間,開始子層動畫.
UIViewAnimationOptionBeginFromCurrentState
//重復(fù)執(zhí)行動畫栗恩,從開始到結(jié)束透乾, 結(jié)束后直接跳到開始態(tài)
UIViewAnimationOptionRepeat
//反向執(zhí)行動畫,結(jié)束后會再從結(jié)束態(tài)->開始態(tài)
UIViewAnimationOptionAutoreverse
//忽略繼承自父層持續(xù)時間磕秤,使用自己持續(xù)時間(如果存在)
UIViewAnimationOptionOverrideInheritedDuration
//忽略繼承自父層的線性效果乳乌,使用自己的線性效果(如果存在)
UIViewAnimationOptionOverrideInheritedCurve
//允許同一個view的多個動畫同時進行     
UIViewAnimationOptionAllowAnimatedContent     
//視圖切換時直接隱藏舊視圖、顯示新視圖市咆,而不是將舊視圖從父視圖移除(僅僅適用于轉(zhuǎn)場動畫)             UIViewAnimationOptionShowHideTransitionViews
//不繼承父動畫設(shè)置或動畫類型.
UIViewAnimationOptionOverrideInheritedOptions

這下可以看到,這些枚舉功能都不一樣但是可以隨意組合,但是組合的時候需要注意,同一類型的枚舉不能一起使用比如UIViewAnimationOptionCurveEaseInUIViewAnimationOptionCurveEaseOut

然后我們看一下轉(zhuǎn)場動畫的一些效果:

單視圖轉(zhuǎn)場

單視圖轉(zhuǎn)場.gif

雙視圖轉(zhuǎn)場

雙視圖轉(zhuǎn)場.gif

CATransition視圖轉(zhuǎn)場

CATransition.gif

動畫效果太多,gif錄不了太大,效果沒有一一展示.然后代碼再這里:demo-轉(zhuǎn)場動畫

除了3D變換動畫,和繪圖相關(guān)的動畫,基本上我們常用到的動畫都在這里了.另外感謝這些參考博客的博主~
http://www.reibang.com/p/ab0e7b291468
http://www.cocoachina.com/ios/20150105/10812.html
http://www.reibang.com/p/240398d0609d
http://www.reibang.com/p/c18588d4104a
http://www.reibang.com/p/499a0689ec40
http://www.reibang.com/p/a079a9bb20f9
http://www.reibang.com/p/08fa17620dae
http://www.reibang.com/p/90a7a1787d1b

在篇尾

程序員不需要打賞汉操,只希望自己的項目能幫助更多人,請支持我的git開源框架:TFEasyCoder

原創(chuàng)內(nèi)容,轉(zhuǎn)載請注明出處:

http://www.reibang.com/p/3f48fabaca19

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒙兰,一起剝皮案震驚了整個濱河市磷瘤,隨后出現(xiàn)的幾起案子芒篷,更是在濱河造成了極大的恐慌,老刑警劉巖采缚,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件针炉,死亡現(xiàn)場離奇詭異,居然都是意外死亡仰担,警方通過查閱死者的電腦和手機糊识,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摔蓝,“玉大人,你說我怎么就攤上這事愉耙≈荆” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵朴沿,是天一觀的道長猜谚。 經(jīng)常有香客問我,道長赌渣,這世上最難降的妖魔是什么魏铅? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮坚芜,結(jié)果婚禮上览芳,老公的妹妹穿的比我還像新娘。我一直安慰自己鸿竖,他們只是感情好沧竟,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缚忧,像睡著了一般悟泵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闪水,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天糕非,我揣著相機與錄音,去河邊找鬼球榆。 笑死朽肥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的芜果。 我是一名探鬼主播鞠呈,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼右钾!你這毒婦竟也來了蚁吝?” 一聲冷哼從身側(cè)響起旱爆,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窘茁,沒想到半個月后怀伦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡山林,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年房待,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驼抹。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡桑孩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出框冀,到底是詐尸還是另有隱情流椒,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布明也,位于F島的核電站宣虾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏温数。R本人自食惡果不足惜绣硝,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撑刺。 院中可真熱鬧鹉胖,春花似錦、人聲如沸猜煮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽王带。三九已至淑蔚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間愕撰,已是汗流浹背刹衫。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留搞挣,地道東北人带迟。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像囱桨,于是被迫代替她去往敵國和親仓犬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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