iOS CAAnimation動(dòng)畫(huà)初探

先看看CAAnimation動(dòng)畫(huà)的繼承結(jié)構(gòu)

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

CAAnimation基本屬性詳解

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

以上屬性詳解:

  • delegate:動(dòng)畫(huà)執(zhí)行的代理,在動(dòng)畫(huà)開(kāi)始前設(shè)定,不用顯式的寫(xiě)在代碼里,它包含兩個(gè)方法:

動(dòng)畫(huà)開(kāi)始回調(diào)
- (void)animationDidStart:(CAAnimation *)aim;
動(dòng)畫(huà)結(jié)束回調(diào)
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

  • removedOnCompletion:動(dòng)畫(huà)完成后是否移除動(dòng)畫(huà).默認(rèn)為YES.此屬性為YES時(shí), fillMode不可用,具體為什么不可用,可以自己結(jié)合兩個(gè)屬性分析一下,這里不再贅述.
  • timingFunction 設(shè)置動(dòng)畫(huà)速度曲線,默認(rèn)值上面已經(jīng)給出.下面說(shuō)它的幾個(gè)方法:

這兩個(gè)方法是一樣的.如果我們對(duì)系統(tǒng)自帶的速度函數(shù)不滿意,可以通過(guò)這兩個(gè)函數(shù)創(chuàng)建一個(gè)自己喜歡的速度曲線函數(shù),具體用法可以參考這篇文章CAMediaTimingFunction的使用

+ (instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
- (instancetype)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;

獲取曲線函數(shù)的緩沖點(diǎn),具體用法可以參考這篇文章:iOS-核心動(dòng)畫(huà)高級(jí)編程/10-緩沖
- (void)getControlPointAtIndex:(size_t)idx values:(float[2])ptr;

CAAnimation協(xié)議的屬性

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

以上屬性的詳解:

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

CAPropertyAnimation的基本屬性

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

以上屬性的詳解:

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

  • valueFunction:我們來(lái)看它可以設(shè)置的值:
kCAValueFunctionRotateX
kCAValueFunctionRotateY
kCAValueFunctionRotateZ
kCAValueFunctionScale
kCAValueFunctionScaleX
kCAValueFunctionScaleY
kCAValueFunctionScaleZ
kCAValueFunctionTranslate
kCAValueFunctionTranslateX
kCAValueFunctionTranslateY
kCAValueFunctionTranslateZ```

CAPropertyAnimation的方法

//通過(guò)key創(chuàng)建一個(gè)CAPropertyAnimation對(duì)象

  • (instancetype)animationWithKeyPath:(nullable NSString *)path;
下面我們來(lái)看一下可以設(shè)置屬性動(dòng)畫(huà)的屬性歸總:

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**是基類(lèi),* *CAPropertyAnimation**是抽象類(lèi),兩者都不可以直接使用, 那我們只有使用它的子類(lèi)了.

## CABasicAnimation基本動(dòng)畫(huà)

### CABasicAnimation的屬性

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


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

* fromValue和toValue不為空,動(dòng)畫(huà)的效果會(huì)從fromValue的值變化到toValue.
* fromValue和byValue都不為空,動(dòng)畫(huà)的效果將會(huì)從fromValue變化到fromValue+byValue
* toValue和byValue都不為空,動(dòng)畫(huà)的效果將會(huì)從toValue-byValue變化到toValue
* 只有fromValue的值不為空,動(dòng)畫(huà)的效果將會(huì)從fromValue的值變化到當(dāng)前的狀態(tài).
* 只有toValue的值不為空,動(dòng)畫(huà)的效果將會(huì)從當(dāng)前狀態(tài)的值變化到toValue的值.
* 只有byValue的值不為空,動(dòng)畫(huà)的效果將會(huì)從當(dāng)前的值變化到(當(dāng)前狀態(tài)的值+byValue)的值.

CABasicAnimation看起來(lái)不太復(fù)雜,但實(shí)際只用這個(gè)就足以可以做很多種動(dòng)畫(huà)了,下面簡(jiǎn)單用一下,先看效果:
        
![CABasicAnimation.gif](http://upload-images.jianshu.io/upload_images/2455429-518087d3167a598f.gif?imageMogr2/auto-orient/strip)

實(shí)現(xiàn)代碼:
  • (IBAction)animation:(id)sender
    {
    UIButton *btn = (UIButton *)sender;
    CABasicAnimation *animation = nil;

    switch (btn.tag)
    {
    //淡如淡出
    case 0:
    animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    [animation setFromValue:@1];
    [animation setToValue:@0.1];
    break;
    //縮放
    case 1:
    animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    [animation setFromValue:@1];
    [animation setToValue:@0.1];
    break;
    //旋轉(zhuǎn)
    case 2:
    animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    [animation setToValue:@(M_PI)];
    break;
    //平移
    case 3:
    animation = [CABasicAnimation animationWithKeyPath:@"position"];
    [animation setToValue:[NSValue valueWithCGPoint:CGPointMake(self.opView.center.x, self.opView.center.y+200)]];
    break;
    default:
    break;
    }

    animation.delegate = self;
    animation.duration = 0.3;//設(shè)置動(dòng)畫(huà)時(shí)間,單次動(dòng)畫(huà)時(shí)間
    animation.removedOnCompletion = NO;//默認(rèn)為YES,設(shè)置為NO時(shí)setFillMode有效

    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

    //設(shè)置自動(dòng)翻轉(zhuǎn)
    //設(shè)置自動(dòng)翻轉(zhuǎn)以后單次動(dòng)畫(huà)時(shí)間不變,總動(dòng)畫(huà)時(shí)間增加一倍涛菠,它會(huì)讓你前半部分的動(dòng)畫(huà)以相反的方式動(dòng)畫(huà)過(guò)來(lái)
    //比如說(shuō)你設(shè)置執(zhí)行一次動(dòng)畫(huà)俗冻,從a到b時(shí)間為1秒迄薄,設(shè)置自動(dòng)翻轉(zhuǎn)以后動(dòng)畫(huà)的執(zhí)行方式為涣易,先從a到b執(zhí)行一秒新症,然后從b到a再執(zhí)行一下動(dòng)畫(huà)結(jié)束
    [animation setAutoreverses:YES];

    //kCAFillModeForwards//動(dòng)畫(huà)結(jié)束后回到準(zhǔn)備狀態(tài)
    //kCAFillModeBackwards//動(dòng)畫(huà)結(jié)束后保持最后狀態(tài)
    //kCAFillModeBoth//動(dòng)畫(huà)結(jié)束后回到準(zhǔn)備狀態(tài),并保持最后狀態(tài)
    //kCAFillModeRemoved//執(zhí)行完成移除動(dòng)畫(huà)
    [animation setFillMode:kCAFillModeBoth];

    //將動(dòng)畫(huà)添加到layer,添加到圖層開(kāi)始執(zhí)行動(dòng)畫(huà)徒爹,
    //注意:key值的設(shè)置與否會(huì)影響動(dòng)畫(huà)的效果
    //如果不設(shè)置key值每次執(zhí)行都會(huì)創(chuàng)建一個(gè)動(dòng)畫(huà)隆嗅,然后創(chuàng)建的動(dòng)畫(huà)會(huì)疊加在圖層上
    //如果設(shè)置key值胖喳,系統(tǒng)執(zhí)行這個(gè)動(dòng)畫(huà)時(shí)會(huì)先檢查這個(gè)動(dòng)畫(huà)有沒(méi)有被創(chuàng)建,如果沒(méi)有的話就創(chuàng)建一個(gè)技健,如果有的話就重新從頭開(kāi)始執(zhí)行這個(gè)動(dòng)畫(huà)
    //你可以通過(guò)key值獲取或者刪除一個(gè)動(dòng)畫(huà):
    [self.opView.layer addAnimation:animation forKey:@"baseanimation"];
    }

###CASpringAnimation彈性動(dòng)畫(huà)
**CASpringAnimation的**屬性(iOS9新加)

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


下面我們寫(xiě)一個(gè)demo看看效果:


![](//upload-images.jianshu.io/upload_images/2455429-953b571f7664e583.gif)

實(shí)現(xiàn)代碼:
  • (IBAction)animationBegin:(id)sender
    {
    UIButton *btn = (UIButton *)sender;

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

    btn.selected = !btn.selected;
    }


### CAKeyframeAnimation關(guān)鍵幀動(dòng)畫(huà)
**CAKeyframeAnimation**的屬性

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


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


![](//upload-images.jianshu.io/upload_images/2455429-4d17bc8a5d9b2bb1.gif)

實(shí)現(xiàn)代碼:
  • (IBAction)animationBegin:(id)sender {
    UIButton *btn = (UIButton *)sender;
    switch (btn.tag) {
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    [self path:btn.tag];break;
    case 6:
    case 7:
    [self values:btn.tag];break;

      default:
          break;
    

    }
    }

-(void)path:(NSInteger)tag{

CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];

switch (tag) {
    case 0:{
        //橢圓
        CGMutablePathRef path = CGPathCreateMutable();//創(chuàng)建可變路徑
        CGPathAddEllipseInRect(path, NULL, CGRectMake(0, 0, 320, 500));
        [animation setPath:path];
        CGPathRelease(path);
        animation.rotationMode = kCAAnimationRotateAuto;
        
    }break;
    case 1:{
        //貝塞爾,矩形
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 320, 320)];
        //animation需要的類(lèi)型是CGPathRef款票,UIBezierPath是ui的,需要轉(zhuǎn)化成CGPathRef
        [animation setPath:path.CGPath];
        
        
    }break;
    case 2:{
        //貝塞爾,拋物線
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:self.opView.center];
        [path addQuadCurveToPoint:CGPointMake(0, 568)
                     controlPoint:CGPointMake(400, 100)];
        [animation setPath:path.CGPath];
        
    }break;
    case 3:{
        //貝塞爾,s形曲線
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:CGPointZero];
        [path addCurveToPoint:self.opView.center
                controlPoint1:CGPointMake(320, 100)
                controlPoint2:CGPointMake(  0, 400)];
        ;
        [animation setPath:path.CGPath];
        
        
    }break;
    case 4:{
        //貝塞爾,圓形
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:self.view.center
                                                            radius:150
                                                        startAngle:- M_PI * 0.5
                                                          endAngle:M_PI * 2
                                                         clockwise:YES];
        [animation setPath:path.CGPath];
        
        
    }break;
    case 5:{
        CGPoint point = CGPointMake(self.view.center.x, 400);
        CGFloat xlength = point.x - self.opView.center.x;
        CGFloat ylength = point.y - self.opView.center.y;
        
        CGMutablePathRef path = CGPathCreateMutable();
        //移動(dòng)到目標(biāo)點(diǎn)
        CGPathMoveToPoint(path, NULL, self.opView.center.x, self.opView.center.y);
        //將目標(biāo)點(diǎn)的坐標(biāo)添加到路徑中
        CGPathAddLineToPoint(path, NULL, point.x, point.y);
        //設(shè)置彈力因子,
        CGFloat offsetDivider = 5.0f;
        BOOL stopBounciong = NO;
        while (stopBounciong == NO) {
            CGPathAddLineToPoint(path, NULL, point.x + xlength / offsetDivider, point.y + ylength / offsetDivider);
            CGPathAddLineToPoint(path, NULL, point.x, point.y);
            offsetDivider += 6.0;
            //當(dāng)視圖的當(dāng)前位置距離目標(biāo)點(diǎn)足夠小我們就退出循環(huán)
            if ((ABS(xlength / offsetDivider) < 10.0f) && (ABS(ylength / offsetDivider) < 10.0f)) {
                break;
            }
        }
        [animation setPath:path];
        
    }break;
    default:break;
}

[animation setDuration:0.5];
[animation setRemovedOnCompletion:NO];
[animation setFillMode:kCAFillModeBoth];
[self.opView.layer addAnimation:animation forKey:nil];

}

-(void)values:(NSInteger)tag{

CAKeyframeAnimation *animation = nil;
switch (tag) {
    case 6:{
        animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
        
        CGFloat angle = M_PI_4 * 0.5;
        NSArray *values = @[@(angle),@(-angle),@(angle)];
        [animation setValues:values];
        [animation setRepeatCount:3];
        [animation setDuration:0.5];
    }break;
    case 7:{
        
        
        animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        NSValue *p1 = [NSValue valueWithCGPoint:self.opView.center];
        NSValue *p2 = [NSValue valueWithCGPoint:CGPointMake(self.view.center.x + 100, 200)];
        NSValue *p3 = [NSValue valueWithCGPoint:CGPointMake(self.view.center.x, 300)];
        //設(shè)置關(guān)鍵幀的值
        [animation setValues:@[p1,p2,p3]];
        [animation setDuration:0.5];
    }break;
    default:break;
}

UIGraphicsBeginImageContext(self.view.frame.size);
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[animation setRemovedOnCompletion:NO];
[animation setFillMode:kCAFillModeBoth];
[self.opView.layer addAnimation:animation forKey:nil];

}

### CAAnimationGroup動(dòng)畫(huà)組
**CAAnimationGroup**的屬性

//只有一個(gè)屬性,數(shù)組中接受CAAnimation元素
@property(nullable, copy) NSArray *animations;

可以看到CAAnimationGroup只有一個(gè)屬性一個(gè)CAAnimation數(shù)組.而且它繼承于CAAnimation,它具有CAAnimation的特性,所以它的用法和CAAnimation是一樣的,不同的是他可以包含n個(gè)動(dòng)畫(huà),也就是說(shuō)他可以接受很多個(gè)CAAnimation并且可以讓它們一起開(kāi)始,這就造成了動(dòng)畫(huà)效果的疊加,效果就是n個(gè)動(dòng)畫(huà)同時(shí)進(jìn)行.

來(lái)看一個(gè)簡(jiǎn)單的效果:


![](//upload-images.jianshu.io/upload_images/2455429-5cce294ff5a60e70.gif)

實(shí)現(xiàn)代碼:
  • (IBAction)animationBegin:(id)sender
    {
    CAAnimationGroup *group = [CAAnimationGroup animation];

    /**

    • 移動(dòng)動(dòng)畫(huà)
      /
      CAKeyframeAnimation position = [self moveAnimation];
      /
    • 搖晃動(dòng)畫(huà)
      /
      CAKeyframeAnimation shake = [self shakeAnimation];
      /
    • 透明度動(dòng)畫(huà)
      /
      CABasicAnimation alpha = [self alphaAnimation];
      /
    • 設(shè)置動(dòng)畫(huà)組的時(shí)間,這個(gè)時(shí)間表示動(dòng)畫(huà)組的總時(shí)間,它的子動(dòng)畫(huà)的時(shí)間和這個(gè)時(shí)間沒(méi)有關(guān)系
      */
      [group setDuration:3.0];
      [group setAnimations:@[position,shake,alpha]];
      [self.opView.layer addAnimation:group forKey:nil];
      }

pragma mark -- CAKeyframeAnimation - 路徑平移動(dòng)畫(huà)

-(CAKeyframeAnimation )moveAnimation
{
CAKeyframeAnimation animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
/

* 設(shè)置路徑鹦赎,按圓運(yùn)動(dòng)
*/
CGMutablePathRef path = CGPathCreateMutable();//CG是C語(yǔ)言的框架古话,需要直接寫(xiě)語(yǔ)法
CGPathAddEllipseInRect(path, NULL, CGRectMake(0, 0, 320, 320));
[animation setPath:path];//把路徑給動(dòng)畫(huà)
CGPathRelease(path);//釋放路徑

/**
 *  設(shè)置動(dòng)畫(huà)時(shí)間陪踩,這是動(dòng)畫(huà)總時(shí)間膊毁,不是每一幀的時(shí)間
 */
[animation setDuration:3];
/**
 *setRemovedOnCompletion 設(shè)置動(dòng)畫(huà)完成后是否將圖層移除掉婚温,默認(rèn)是移除
 *setFillMode 當(dāng)前設(shè)置的是向前填充栅螟,意味著動(dòng)畫(huà)完成后填充效果為最新的效果,此屬性有效的前提是 setRemovedOnCompletion=NO
 *注意:
 *1.動(dòng)畫(huà)只是改變?nèi)说囊曈X(jué)吃媒,它并不會(huì)改變視圖的初始位置等信息赘那,也就是說(shuō)無(wú)論動(dòng)畫(huà)怎么東募舟,都不會(huì)改變view的原始大小拱礁,只是看起來(lái)像是大小改變了而已
 *2.因?yàn)闆](méi)有改變視圖的根本大小呢灶,所以視圖所接收事件的位置還是原來(lái)的大小鸯乃,可以不是顯示的大小
 */
[animation setRemovedOnCompletion:NO];
[animation setFillMode:kCAFillModeForwards];
return animation;

}

pragma mark -- CAKeyframeAnimation - 搖晃動(dòng)畫(huà)

-(CAKeyframeAnimation )shakeAnimation
{
CAKeyframeAnimation animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
/

* 設(shè)置路徑飒责,貝塞爾路徑
/
CGFloat angle = M_PI_4 * 0.1;
NSArray values = @[@(angle),@(-angle),@(angle)];
[animation setValues:values];
[animation setRepeatCount:10];
/

* 設(shè)置動(dòng)畫(huà)時(shí)間宏蛉,這是動(dòng)畫(huà)總時(shí)間揍堰,不是每一幀的時(shí)間
*/
[animation setDuration:0.25];
return animation;
}

pragma mark -- CABasicAnimation - 淡如淡出動(dòng)畫(huà)

-(CABasicAnimation )alphaAnimation
{
CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
[animation setDuration:1.0];
/

* 設(shè)置重復(fù)次數(shù)
/
[animation setRepeatCount:3];
/
*
* 設(shè)置自動(dòng)翻轉(zhuǎn)
* 設(shè)置自動(dòng)翻轉(zhuǎn)以后單次動(dòng)畫(huà)時(shí)間不變屏歹,總動(dòng)畫(huà)時(shí)間延遲一倍蝙眶,它會(huì)讓你前半部分的動(dòng)畫(huà)以相反的方式動(dòng)畫(huà)過(guò)來(lái)
* 比如說(shuō)你設(shè)置執(zhí)行一次動(dòng)畫(huà)幽纷,從a到b時(shí)間為1秒友浸,設(shè)置自動(dòng)翻轉(zhuǎn)以后動(dòng)畫(huà)的執(zhí)行方式為收恢,先從a到b執(zhí)行一秒,然后從b到a再執(zhí)行一下動(dòng)畫(huà)結(jié)束
/
[animation setAutoreverses:YES];
/
*
* 設(shè)置起始值
/
[animation setFromValue:@1.0];
/
*
* 設(shè)置目標(biāo)值
/
[animation setToValue:@0.1];
/
*
* 將動(dòng)畫(huà)添加到layer 添加到圖層開(kāi)始執(zhí)行動(dòng)畫(huà)默赂,
* 注意:key值的設(shè)置與否會(huì)影響動(dòng)畫(huà)的效果
* 如果不設(shè)置key值每次執(zhí)行都會(huì)創(chuàng)建一個(gè)動(dòng)畫(huà),然后創(chuàng)建的動(dòng)畫(huà)會(huì)疊加在圖層上
* 如果設(shè)置key值疾捍,系統(tǒng)執(zhí)行這個(gè)動(dòng)畫(huà)時(shí)會(huì)先檢查這個(gè)動(dòng)畫(huà)有沒(méi)有被創(chuàng)建乱豆,如果沒(méi)有的話就創(chuàng)建一個(gè)瑟啃,如果有的話就重新從頭開(kāi)始執(zhí)行這個(gè)動(dòng)畫(huà)
* 你可以通過(guò)key值獲取或者刪除一個(gè)動(dòng)畫(huà)
*/
return animation;
}


### CATransition轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
**CATransition**屬性

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

**CATransition**也是繼承**CAAnimation**,系統(tǒng)默認(rèn)提供了12種動(dòng)畫(huà)樣式,加上4個(gè)動(dòng)畫(huà)方向,除了方向不可控的四種效果外,大概一共提供了36種動(dòng)畫(huà).
另外系統(tǒng)還給UIView添加了很多分類(lèi)方法可以快速完成一些簡(jiǎn)單的動(dòng)畫(huà),如下:

**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
    //提交動(dòng)畫(huà)
  • (void)commitAnimations;
    //設(shè)置代理
  • (void)setAnimationDelegate:(nullable id)delegate; //設(shè)置動(dòng)畫(huà)開(kāi)始方法
  • (void)setAnimationWillStartSelector:(nullable SEL)selector;
    //設(shè)置動(dòng)畫(huà)結(jié)束方法
  • (void)setAnimationDidStopSelector:(nullable SEL)selector;
    //設(shè)置動(dòng)畫(huà)時(shí)間:default = 0.2
  • (void)setAnimationDuration:(NSTimeInterval)duration;
    //設(shè)置動(dòng)畫(huà)延遲開(kāi)始時(shí)間:default = 0.0
  • (void)setAnimationDelay:(NSTimeInterval)delay;
    //設(shè)置動(dòng)畫(huà)延遲開(kāi)始日期:default = now ([NSDate date])
  • (void)setAnimationStartDate:(NSDate *)startDate;
    //設(shè)置動(dòng)畫(huà)運(yùn)動(dòng)曲線:default =UIViewAnimationCurveEaseInOut
    //UIViewAnimationCurveEaseInOut,//慢進(jìn)慢出
    //UIViewAnimationCurveEaseIn, //慢進(jìn)快出
    //UIViewAnimationCurveEaseOut,//快進(jìn)慢出
    //UIViewAnimationCurveLinear//勻速
  • (void)setAnimationCurve:(UIViewAnimationCurve)curve;
    //設(shè)置重復(fù)次數(shù): default = 0.0. May be fractional
  • (void)setAnimationRepeatCount:(float)repeatCount;
    //設(shè)置是否翻轉(zhuǎn)動(dòng)畫(huà): default = NO. used if repeat
  • (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
    //設(shè)置動(dòng)畫(huà)是否從當(dāng)前狀態(tài)開(kāi)始:default = NO
  • (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;
    //設(shè)置動(dòng)畫(huà)類(lèi)型
  • (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
    //設(shè)置動(dòng)畫(huà)是否有效
  • (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 *)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
以上方法比較多,找值得說(shuō)的簡(jiǎn)單說(shuō)一下吧:

//單視圖轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

  • (void)transitionWithView:(UIView *)view
    duration:(NSTimeInterval)duration
    options:(UIViewAnimationOptions)options
    animations:(void (^ __nullable)(void))animations
    completion:(void (^ __nullable)(BOOL finished))completion
    //雙視圖轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
  • (void)transitionFromView:(UIView *)fromView
    toView:(UIView *)toView
    duration:(NSTimeInterval)duration
    options:(UIViewAnimationOptions)options
    completion:(void (^ __nullable)(BOOL finished))completion
這兩個(gè)都是轉(zhuǎn)場(chǎng)動(dòng)畫(huà),不同的是第一個(gè)是單視圖轉(zhuǎn)場(chǎng),第二個(gè)是雙視圖轉(zhuǎn)場(chǎng).不過(guò)需要注意的是:單視圖轉(zhuǎn)場(chǎng)動(dòng)畫(huà)只能用作屬性動(dòng)畫(huà)做不到的轉(zhuǎn)場(chǎng)效果,比如屬性動(dòng)畫(huà)不能給UIImageview的image賦值操作做動(dòng)畫(huà)效果等.
我們可以看到以上兩個(gè)方法中都有一個(gè)共同的參數(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)給到的是一個(gè)位移枚舉,這就意味著這個(gè)枚舉可以多個(gè)值同時(shí)使用,但是怎么用呢?其實(shí)那些枚舉值可以分為三個(gè)部分.
我們分別看一下每個(gè)枚舉的意思:

**第一部分:動(dòng)畫(huà)效果**

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

**第二部分:動(dòng)畫(huà)運(yùn)動(dòng)曲線**

//開(kāi)始慢犹撒,加速到中間识颊,然后減慢到結(jié)束
UIViewAnimationOptionCurveEaseInOut
//開(kāi)始慢谊囚,加速到結(jié)束
UIViewAnimationOptionCurveEaseIn
//開(kāi)始快镰踏,減速到結(jié)束
UIViewAnimationOptionCurveEaseOut
//線性運(yùn)動(dòng)
UIViewAnimationOptionCurveLinear

**第三部分:其他**

//默認(rèn),跟父類(lèi)作為一個(gè)整體
UIViewAnimationOptionLayoutSubviews
//設(shè)置了這個(gè)绊率,主線程可以接收點(diǎn)擊事件
UIViewAnimationOptionAllowUserInteraction
//從當(dāng)前狀態(tài)開(kāi)始動(dòng)畫(huà)滤否,父層動(dòng)畫(huà)運(yùn)動(dòng)期間藐俺,開(kāi)始子層動(dòng)畫(huà).
UIViewAnimationOptionBeginFromCurrentState
//重復(fù)執(zhí)行動(dòng)畫(huà)欲芹,從開(kāi)始到結(jié)束菱父, 結(jié)束后直接跳到開(kāi)始態(tài)

**UIViewAnimationOptionRepeat**

//反向執(zhí)行動(dòng)畫(huà)浙宜,結(jié)束后會(huì)再?gòu)慕Y(jié)束態(tài)->開(kāi)始態(tài)
UIViewAnimationOptionAutoreverse
//忽略繼承自父層持續(xù)時(shí)間粟瞬,使用自己持續(xù)時(shí)間(如果存在)
UIViewAnimationOptionOverrideInheritedDuration
//忽略繼承自父層的線性效果乓梨,使用自己的線性效果(如果存在)
UIViewAnimationOptionOverrideInheritedCurve
//允許同一個(gè)view的多個(gè)動(dòng)畫(huà)同時(shí)進(jìn)行
UIViewAnimationOptionAllowAnimatedContent
//視圖切換時(shí)直接隱藏舊視圖扶镀、顯示新視圖臭觉,而不是將舊視圖從父視圖移除(僅僅適用于轉(zhuǎn)場(chǎng)動(dòng)畫(huà)) UIViewAnimationOptionShowHideTransitionViews
//不繼承父動(dòng)畫(huà)設(shè)置或動(dòng)畫(huà)類(lèi)型.
UIViewAnimationOptionOverrideInheritedOptions

這下可以看到,這些枚舉功能都不一樣但是可以隨意組合,但是組合的時(shí)候需要注意,同一類(lèi)型的枚舉不能一起使用比如UIViewAnimationOptionCurveEaseIn和UIViewAnimationOptionCurveEaseOut
然后我們看一下轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的一些效果:

**單視圖轉(zhuǎn)場(chǎng)**


![單視圖轉(zhuǎn)場(chǎng).gif](http://upload-images.jianshu.io/upload_images/2455429-9b985706162c02b9.gif?imageMogr2/auto-orient/strip)

**雙視圖轉(zhuǎn)場(chǎng)**


![雙視圖轉(zhuǎn)場(chǎng).gif](http://upload-images.jianshu.io/upload_images/2455429-64442b994e0d1b76.gif?imageMogr2/auto-orient/strip)

**CATransition轉(zhuǎn)場(chǎng)**


![CATransition轉(zhuǎn)場(chǎng).gif](http://upload-images.jianshu.io/upload_images/2455429-ef67070f27e696f1.gif?imageMogr2/auto-orient/strip)

實(shí)現(xiàn)代碼:
  • (IBAction)animationBegin:(id)sender
    {
    UIButton *btn = (UIButton *)sender;
    switch (btn.tag)
    {
    case 0:
    [self animationSingleView:YES];
    break;
    case 1:
    [self animationSingleView:NO];
    break;
    case 2:[self chang3];
    break;
    default:break;
    }
    }

/**

  • 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)在執(zhí)行過(guò)程中不可以被停止,
  • 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)在執(zhí)行過(guò)程中不可以用戶(hù)交互
  • 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)在執(zhí)行過(guò)程中不可以控制動(dòng)畫(huà)執(zhí)行進(jìn)度
    /
    /
    *
  • 基于UIView的單視圖轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
    */
    static NSUInteger change1_0Index = 0;
    static NSUInteger change1_1Index = 0;
    static NSUInteger change1_2Index = 0;

-(void)animationSingleView:(BOOL)sigle
{
/**
* 第一部分
*/
NSArray *array0 = @[
@(UIViewAnimationOptionTransitionNone),
@(UIViewAnimationOptionTransitionFlipFromLeft),//從左水平翻轉(zhuǎn)
@(UIViewAnimationOptionTransitionFlipFromRight),//從右水平翻轉(zhuǎn)
@(UIViewAnimationOptionTransitionCurlUp),//翻書(shū)上掀
@(UIViewAnimationOptionTransitionCurlDown),//翻書(shū)下蓋
@(UIViewAnimationOptionTransitionCrossDissolve),//融合
@(UIViewAnimationOptionTransitionFlipFromTop),//從上垂直翻轉(zhuǎn)
@(UIViewAnimationOptionTransitionFlipFromBottom),//從下垂直翻轉(zhuǎn)
];

/**
 *  第二部分
 */
NSArray *array1 = @[
                    @(UIViewAnimationOptionCurveEaseInOut),////開(kāi)始慢什乙,加速到中間,然后減慢到結(jié)束
                    @(UIViewAnimationOptionCurveEaseIn),//開(kāi)始慢忆某,加速到結(jié)束
                    @(UIViewAnimationOptionCurveEaseOut),//開(kāi)始快弃舒,減速到結(jié)束
                    @(UIViewAnimationOptionCurveLinear),//線性運(yùn)動(dòng)
                    ];

/**
 *  第三部分
 */
NSArray *array2 = @[
                    @(UIViewAnimationOptionLayoutSubviews),//默認(rèn)聋呢,跟父類(lèi)作為一個(gè)整體
                    @(UIViewAnimationOptionAllowUserInteraction),//設(shè)置了這個(gè)坝冕,主線程可以接收點(diǎn)擊事件
                    @(UIViewAnimationOptionBeginFromCurrentState),//從當(dāng)前狀態(tài)開(kāi)始動(dòng)畫(huà),父層動(dòng)畫(huà)運(yùn)動(dòng)期間,開(kāi)始子層動(dòng)畫(huà)央串。
                    @(UIViewAnimationOptionRepeat),//重復(fù)執(zhí)行動(dòng)畫(huà)磨澡,從開(kāi)始到結(jié)束, 結(jié)束后直接跳到開(kāi)始態(tài)
                    @(UIViewAnimationOptionAutoreverse),//反向執(zhí)行動(dòng)畫(huà)质和,結(jié)束后會(huì)再?gòu)慕Y(jié)束態(tài)->開(kāi)始態(tài)
                    @(UIViewAnimationOptionOverrideInheritedDuration),//忽略繼承自父層持續(xù)時(shí)間稳摄,使用自己持續(xù)時(shí)間(如果存在)
                    @(UIViewAnimationOptionOverrideInheritedCurve),//忽略繼承自父層的線性效果,使用自己的線性效果(如果存在)
                    @(UIViewAnimationOptionAllowAnimatedContent),//允許同一個(gè)view的多個(gè)動(dòng)畫(huà)同時(shí)進(jìn)行
                    @(UIViewAnimationOptionShowHideTransitionViews),//視圖切換時(shí)直接隱藏舊視圖饲宿、顯示新視圖,而不是將舊視圖從父視圖移除(僅僅適用于轉(zhuǎn)場(chǎng)動(dòng)畫(huà))
                    @(UIViewAnimationOptionOverrideInheritedOptions),//不繼承父動(dòng)畫(huà)設(shè)置或動(dòng)畫(huà)類(lèi)型瘫想。
                    ];

//    CASpringAnimation
//    CASpringAnimation

if (sigle)
{
    
    [UIView transitionWithView:self.opView1
                      duration:1
                       options:
     ((NSNumber *)array0[change1_0Index]).integerValue|
     ((NSNumber *)array1[change1_1Index]).integerValue|
     ((NSNumber *)array2[change1_2Index]).integerValue
                    animations:^{
                        /**
                         *  單視圖的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)需要在動(dòng)畫(huà)塊中設(shè)置視圖轉(zhuǎn)場(chǎng)前的內(nèi)容和視圖轉(zhuǎn)場(chǎng)后的內(nèi)容
                         */
                        if (self.opView1.tag == 0)
                        {
                            self.opView1.image = [UIImage imageNamed:@"IMG_1730"];
                            self.opView1.tag = 1;
                        }
                        else
                        {
                            self.opView1.image = [UIImage imageNamed:@"93F5E460-9D31-4780-8511-37FF91033402"];
                            self.opView1.tag = 0;
                        }
                    } completion:nil];
    NSLog(@"動(dòng)畫(huà):%s:%@:%@:%@",__func__,@(change1_0Index),@(change1_1Index),@(change1_2Index));
}
else
{
    /**
     *  雙視圖的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
     *  注意:雙視圖的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)實(shí)際上是操作視圖移除和添加到父視圖的一個(gè)過(guò)程仗阅,from視圖必須要有父視圖,to視圖必須不能有父視圖国夜,否則會(huì)出問(wèn)題
     *  比如動(dòng)畫(huà)不準(zhǔn)等
     */
    
    UIImageView *fromView = nil;
    UIImageView *toView = nil;
    
    if (self.opView1.tag == 0)
    {
        fromView = self.opView1;
        toView = self.opView2;
        self.opView1.tag = 1;
    }
    else
    {
        fromView = self.opView2;
        toView = self.opView1;
        self.opView1.tag = 0;
    }
    
    [UIView transitionFromView:fromView
                        toView:toView duration:1.0
                       options:
     ((NSNumber *)array0[change1_0Index]).integerValue|
     ((NSNumber *)array1[change1_1Index]).integerValue|
     ((NSNumber *)array2[change1_2Index]).integerValue
                    completion:^(BOOL finished) {
                        [fromView removeFromSuperview];
                    }];
    [self.view addSubview:toView];
}
change1_0Index += 1;
if (change1_0Index > array0.count - 1)
{
    change1_0Index = 0;
    change1_1Index += 1;
}
if (change1_1Index > array1.count - 1)
{
    change1_1Index = 0;
    change1_2Index += 1;
}
if (change1_2Index > array2.count - 1)
{
    change1_2Index = 0;
    
    change1_0Index = 0;
    change1_2Index = 0;
}

}

/**

  • 基于CATransition的視圖轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
    /
    static NSUInteger change3_0Index = 0;
    static NSUInteger change3_1Index = 0;
    -(void)chang3
    {
    /
    *
    *創(chuàng)建轉(zhuǎn)場(chǎng)動(dòng)畫(huà):注意:CATransaction和CATransition 不一樣
    */
    CATransition *transition = [CATransition animation];

    transition.duration = 0.25;

    NSArray *type_array = @[
    //系統(tǒng)提供的動(dòng)畫(huà)
    kCATransitionFade,
    kCATransitionMoveIn,
    kCATransitionPush,
    kCATransitionReveal,

                        //以下是私有api,只能字符串訪問(wèn)
                        @"cube",//立方體翻轉(zhuǎn)效果
                        @"oglFlip",//翻轉(zhuǎn)效果
                        @"suckEffect",//收縮效果,動(dòng)畫(huà)方向不可控
                        @"rippleEffect",//水滴波紋效果,動(dòng)畫(huà)方向不可控
                        @"pageCurl",//向上翻頁(yè)效果
                        @"pageUnCurl",//向下翻頁(yè)效果
                        @"cameralIrisHollowOpen",//攝像頭打開(kāi)效果,動(dòng)畫(huà)方向不可控
                        @"cameraIrisHollowClose",//攝像頭關(guān)閉效果,動(dòng)畫(huà)方向不可控
                        ];
    

    //轉(zhuǎn)場(chǎng)類(lèi)型
    transition.type = type_array[change3_0Index];

    NSArray *subtype_array = @[
    kCATransitionFromRight,
    kCATransitionFromLeft,
    kCATransitionFromTop,
    kCATransitionFromBottom
    ];
    //轉(zhuǎn)場(chǎng)方向
    transition.subtype = subtype_array[change3_1Index];

    /**

    • 設(shè)置轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的開(kāi)始和結(jié)束百分比
      */
      transition.startProgress = 0.0;
      transition.endProgress = 1.0;
if (self.opView1.tag == 0)
{
    self.opView1.tag = 1;
    
    
    self.opView1.image = [UIImage imageNamed:@"IMG_1730"];
    self.opView2.image = [UIImage imageNamed:@"93F5E460-9D31-4780-8511-37FF91033402"];
}
else
{
    self.opView1.tag = 0;
    
    self.opView1.image = [UIImage imageNamed:@"93F5E460-9D31-4780-8511-37FF91033402"];
    self.opView2.image = [UIImage imageNamed:@"IMG_1730"];
}
[self.opView1.layer addAnimation:transition forKey:nil];
[self.opView2.layer addAnimation:transition forKey:nil];

NSLog(@"動(dòng)畫(huà):%s:%@:%@",__func__,@(change3_0Index),@(change3_1Index));

change3_1Index += 1;
if (change3_1Index > subtype_array.count - 1)
{
    change3_1Index = 0;
    change3_0Index += 1;
}
if (change3_0Index > type_array.count - 1)
{
    change3_0Index = 0;
}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末减噪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子车吹,更是在濱河造成了極大的恐慌筹裕,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窄驹,死亡現(xiàn)場(chǎng)離奇詭異朝卒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)乐埠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)扎运,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人饮戳,你說(shuō)我怎么就攤上這事豪治。” “怎么了扯罐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵负拟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我歹河,道長(zhǎng)掩浙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任秸歧,我火速辦了婚禮厨姚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘键菱。我一直安慰自己谬墙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著拭抬,像睡著了一般部默。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上造虎,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天傅蹂,我揣著相機(jī)與錄音,去河邊找鬼算凿。 笑死份蝴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的氓轰。 我是一名探鬼主播搞乏,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼戒努!你這毒婦竟也來(lái)了请敦?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤储玫,失蹤者是張志新(化名)和其女友劉穎侍筛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體撒穷,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匣椰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了端礼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片禽笑。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蛤奥,靈堂內(nèi)的尸體忽然破棺而出佳镜,到底是詐尸還是另有隱情,我是刑警寧澤凡桥,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布蟀伸,位于F島的核電站,受9級(jí)特大地震影響缅刽,放射性物質(zhì)發(fā)生泄漏啊掏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一衰猛、第九天 我趴在偏房一處隱蔽的房頂上張望迟蜜。 院中可真熱鬧,春花似錦啡省、人聲如沸娜睛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)微姊。三九已至酸茴,卻和暖如春分预,著一層夾襖步出監(jiān)牢的瞬間兢交,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工笼痹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留配喳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓凳干,卻偏偏與公主長(zhǎng)得像晴裹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子救赐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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