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 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í)間,此屬性優(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í)間和它的父類有關(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是基類,CAPropertyAnimation**是抽象類,兩者都不可以直接使用, 那我們只有使用它的子類了.

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

實(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看看效果:


實(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做的效果:


實(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需要的類型是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)單的效果:


實(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)類型,字符串類型參數(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添加了很多分類方法可以快速完成一些簡(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à)類型

+ (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),跟父類作為一個(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à)類型.

UIViewAnimationOptionOverrideInheritedOptions

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

然后我們看一下轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的一些效果:

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


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

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


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

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


CATransition轉(zhuǎn)場(chǎng).gif

實(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ò)程中不可以用戶交互

*? 轉(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),跟父類作為一個(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à)類型。

];

//? ? 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)類型

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;

}

}

作者:xqqlv

鏈接:http://www.lxweimin.com/p/4c3bace804e3

來(lái)源:簡(jiǎn)書(shū)

著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,506評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,614評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,402評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,934評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,168評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,596評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,027評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,404評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,662評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,398評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,743評(píng)論 2 370

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

  • 在iOS實(shí)際開(kāi)發(fā)中常用的動(dòng)畫(huà)無(wú)非是以下四種:UIView動(dòng)畫(huà),核心動(dòng)畫(huà),幀動(dòng)畫(huà),自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。 1.UIView...
    請(qǐng)叫我周小帥閱讀 3,128評(píng)論 1 23
  • 動(dòng)畫(huà)的繼承結(jié)構(gòu) CAAnimation{CAPropertyAnimation{CABasicAnimation{...
    早起的蟲(chóng)兒子被鳥(niǎo)吃閱讀 896評(píng)論 0 1
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫(huà)全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,537評(píng)論 6 30
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫(huà)全貌。在這里你可以看...
    F麥子閱讀 5,130評(píng)論 5 13
  • Core Animation Core Animation,中文翻譯為核心動(dòng)畫(huà),它是一組非常強(qiáng)大的動(dòng)畫(huà)處理API,...
    45b645c5912e閱讀 3,044評(píng)論 0 21