原創(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ī)則
-
fromValue
和toValue
不為空,動畫的效果會從fromValue
的值變化到toValue
. -
fromValue
和byValue
都不為空,動畫的效果將會從fromValue
變化到fromValue+byValue
-
toValue
和byValue
都不為空,動畫的效果將會從toValue-byValue
變化到toValue
- 只有
fromValue
的值不為空,動畫的效果將會從fromValue
的值變化到當前的狀態(tài). - 只有
toValue
的值不為空,動畫的效果將會從當前狀態(tài)的值變化到toValue
的值.
只有byValue
的值不為空,動畫的效果將會從當前的值變化到(當前狀態(tài)的值+byValue
)的值.
CABasicAnimation看起來不太復(fù)雜,但實際只用這個就足以可以做很多種動畫了,下面簡單用一下,先看效果:
然后再看下實現(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看看效果:
以上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)才能使用,這就很操蛋了.以前項目有過這樣的需求,然后就自己寫了一個類似的動畫,效果在下面:
然后上面自定義彈性動畫的代碼在這里:
#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做的效果:
以上效果的代碼都比較簡單,量也比較大,這里就不貼出來了,這里可以下載:demo-關(guān)鍵幀動畫
CAAnimationGroup動畫組
CAAnimationGroup的屬性
//只有一個屬性,數(shù)組中接受CAAnimation元素
@property(nullable, copy) NSArray<CAAnimation *> *animations;
- 可以看到CAAnimationGroup只有一個屬性一個CAAnimation數(shù)組.而且它繼承于CAAnimation,它具有CAAnimation的特性,所以它的用法和CAAnimation是一樣的,不同的是他可以包含n個動畫,也就是說他可以接受很多個CAAnimation并且可以讓它們一起開始,這就造成了動畫效果的疊加,效果就是n個動畫同時進行.
來看一個簡單的效果:
這個是動畫是,旋轉(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
這下可以看到,這些枚舉功能都不一樣但是可以隨意組合,但是組合的時候需要注意,同一類型的枚舉不能一起使用比如UIViewAnimationOptionCurveEaseIn
和UIViewAnimationOptionCurveEaseOut
然后我們看一下轉(zhuǎn)場動畫的一些效果:
單視圖轉(zhuǎn)場
雙視圖轉(zhuǎn)場
CATransition視圖轉(zhuǎn)場
動畫效果太多,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