iOS動畫-從不會到熟練應用
前言
上次總結了多線程的用法,這次再復習下iOS動畫的東西.這次依然先是以api為主,因為好多人還是api好多的東西還不會用.然后中間穿插些例子,例子和代碼文章中都會有.因為篇幅比較長,先列一下大綱.
動畫的繼承結構
CAAnimation{
CAPropertyAnimation{
CABasicAnimation{
CASpringAnimation
}
CAKeyframeAnimation
}
CATransition
CAAnimationGroup
}
CAAnimation(動畫根類,不可以直接使用)
CAAnimation-屬性(復雜點的屬性,下面會有詳細解釋)
//動畫的代理回調,下面會有
@property(nullable, strong) id delegate;
//動畫執行完以后是否移除動畫,默認YES
@property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;
//動畫的動作規則,包含以下值
//kCAMediaTimingFunctionLinear 勻速
//kCAMediaTimingFunctionEaseIn 慢進快出
//kCAMediaTimingFunctionEaseOut 快進慢出
//kCAMediaTimingFunctionEaseInEaseOut 慢進慢出 中間加速
//kCAMediaTimingFunctionDefault 默認
@property(nullable, strong) CAMediaTimingFunction *timingFunction;
以上屬性的詳解:
-
delegate:動畫執行的代理,在動畫開始前設定,不用顯式的寫在代碼里,它包含兩個方法:
動畫開始回調
- (void)animationDidStart:(CAAnimation *)anim;
動畫結束回調
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
-
removedOnCompletion:動畫完成后是否移除動畫.默認為YES.此屬性為YES時, fillMode不可用,具體為什么不可用,可以自己結合兩個屬性分析一下,這里不再贅述.
-
timingFunction 設置動畫速度曲線,默認值上面已經給出.下面說它的幾個方法:
這兩個方法是一樣的.如果我們對系統自帶的速度函數不滿意,可以通過這兩個函數創建一個自己喜歡的速度曲線函數。
+ (instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
- (instancetype)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;</code></pre>
- (void)getControlPointAtIndex:(size_t)idx values:(float[2])ptr;
CAAnimation 協議的屬性
//開始時間.這個屬性比較復雜,傻瓜用法為:CACurrentMediaTime() + x,
//其中x為延遲時間.如果設置 beginTime = CACurrentMediaTime() + 1.0,產生的效果為延遲一秒執行動畫,下面詳解原理
@property CFTimeInterval beginTime;
//動畫執行時間,此屬性和speed有關系speed默認為1.0,如果speed設置為2.0,那么動畫執行時間則為duration*(1.0/2.0).
@property CFTimeInterval duration;
//動畫執行速度,它duration的關系參考上面解釋
@property float speed;
//動畫的時間延遲,這個屬性比較復雜,下面詳解
@property CFTimeInterval timeOffset;
//重復執行次數
@property float repeatCount;
//重復執行時間,此屬性優先級大于repeatCount.也就是說如果repeatDuration設置為1秒重復10次,那么它會在1秒內執行完動畫.
@property CFTimeInterval repeatDuration;
//是否自動翻轉動畫,默認NO.如果設置YES,那么整個動畫的執行效果為A->B->A.
@property BOOL autoreverses;
//動畫的填充方式,默認為: kCAFillModeRemoved,包含以下值
//kCAFillModeForwards//動畫結束后回到準備狀態
//kCAFillModeBackwards//動畫結束后保持最后狀態
//kCAFillModeBoth//動畫結束后回到準備狀態,并保持最后狀態
//kCAFillModeRemoved//執行完成移除動畫
@property(copy) NSString *fillMode;
以上屬性的詳解:
-
beginTime:剛才上面簡單解釋了下這個屬性的用法:CACurrentMediaTime()+ x 會使動畫延遲執行x秒.不知道到這里有沒有人想過如果-x會出現怎么樣效果?假設我們有執行一個3秒的動畫,然后設置beginTime = CACurrentMediaTime()- 1.5那么執行動畫你會發現動畫只會執行后半段,也就是只執行后面的3-1.5s的動畫.為什么會這樣?其實動畫都有一個timeline(時間線)的概念.動畫開始執行都是基于這個時間線的絕對時間,這個時間和它的父類有關(系統的屬性注釋可以看到).默認的CALayer的beginTime為零,如果這個值為零的話,系統會把它設置為CACurrentMediaTime(),那么這個時間就是正常執行動畫的時間:立即執行.所以如果你設置beginTime=CACurrentMediaTime()+x;它會把它的執行時間線推遲x秒,也就是晚執行x秒,如果你beginTime=CACurrentMediaTime()-x;那它開始的時候會從你動畫對應的絕對時間開始執行.
-
timeOffset:時間偏移量,默認為0;既然它是時間偏移量,那么它即和動畫時間相關.這么解釋:假設我們設置一個動畫時間為5s,動畫執行的過程為1->2->3->4->5,這時候如果你設置timeOffset = 2s那么它的執行過程就會變成3->4->5->1->2如果你設置timeOffset = 4s那么它的執行過程就會變成5->1->2->3->4,這么說應該很明白了吧?
CAPropertyAnimation屬性動畫,抽象類,不能直接使用
CAPropertyAnimation的屬性
//需要動畫的屬性值
@property(nullable, copy) NSString *keyPath;
//屬性動畫是否以當前動畫效果為基礎,默認為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可以直接設置[CAPropertyAnimation animationWithKeyPath:@"position"]如果我們設置它的transform(CATransform3D)呢?CATransform3D是一個矩陣,如果我們想為它做動畫怎么辦?下面這個屬性就是用來解決這個問題的.
-
valueFunction:我們來看它可以設置的值:
kCAValueFunctionRotateX
kCAValueFunctionRotateY
kCAValueFunctionRotateZ
kCAValueFunctionScale
kCAValueFunctionScaleX
kCAValueFunctionScaleY
kCAValueFunctionScaleZ
kCAValueFunctionTranslate
kCAValueFunctionTranslateX
kCAValueFunctionTranslateY
kCAValueFunctionTranslateZ
說到這里大家應該都知道該怎么用了吧~.
CAPropertyAnimation的方法
//通過key創建一個CAPropertyAnimation對象
(instancetype)animationWithKeyPath:(nullable NSString *)path;</code></pre>
下面我們來看一下可以設置屬性動畫的屬性歸總:
CATransform3D{
rotation旋轉
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
}
}</code></pre>
總結: CAAnimation是基類, CAPropertyAnimation是抽象類,兩者都不可以直接使用, 那我們只有使用它的子類了.
CABasicAnimation基本動畫
CABasicAnimation的屬性
//開始值
@property(nullable, strong) id fromValue;
//結束值
@property(nullable, strong) id toValue;
//結束值
@property(nullable, strong) id byValue;
這三個屬性之間的規則
-
fromValue和toValue不為空,動畫的效果會從fromValue的值變化到toValue.
-
fromValue和byValue都不為空,動畫的效果將會從fromValue變化到fromValue+byValue
-
toValue和byValue都不為空,動畫的效果將會從toValue-byValue變化到toValue
-
只有fromValue的值不為空,動畫的效果將會從fromValue的值變化到當前的狀態.
-
只有toValue的值不為空,動畫的效果將會從當前狀態的值變化到toValue的值.
-
只有byValue的值不為空,動畫的效果將會從當前的值變化到(當前狀態的值+byValue)的值.
CABasicAnimation看起來不太復雜,但實際只用這個就足以可以做很多種動畫了,下面簡單用一下,先看效果:

CABasicAnimation.gif
然后再看下實現代碼:
#import "ViewController.h"
import "TFEasyCoder.h"
@interface ViewController ()
@property (nonatomic,strong)UIView *demoView;
@end
@implementation ViewController
(void)viewDidLoad {
[super viewDidLoad];
kdeclare_weakself;
NSArray *titles = @[@"淡入淡出",@"縮放",@"旋轉",@"平移"];
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];//設置起始值
[animation setToValue:@0.1];//設置目標值
}break;
case 2:{
//旋轉
animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
//setFromValue不設置,默認以當前狀態為準
[animation setToValue:@(M_PI)];
}break;
case 3:{
//平移
animation = [CABasicAnimation animationWithKeyPath:@"position"];
//setFromValue不設置,默認以當前狀態為準
[animation setToValue:[NSValue valueWithCGPoint:CGPointMake(self.view.center.x, self.view.center.y + 200)]];
}break;
default:break;
}
[animation setDelegate:self];//代理回調
[animation setDuration:0.25];//設置動畫時間,單次動畫時間
[animation setRemovedOnCompletion:NO];//默認為YES,設置為NO時setFillMode有效
/*
設置時間函數CAMediaTimingFunction
kCAMediaTimingFunctionLinear 勻速
kCAMediaTimingFunctionEaseIn 開始速度慢,后來速度快
kCAMediaTimingFunctionEaseOut 開始速度快 后來速度慢
kCAMediaTimingFunctionEaseInEaseOut = kCAMediaTimingFunctionDefault 中間速度快,兩頭速度慢
*/
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
//設置自動翻轉
//設置自動翻轉以后單次動畫時間不變,總動畫時間增加一倍,它會讓你前半部分的動畫以相反的方式動畫過來
//比如說你設置執行一次動畫,從a到b時間為1秒,設置自動翻轉以后動畫的執行方式為,先從a到b執行一秒,然后從b到a再執行一下動畫結束
[animation setAutoreverses:YES];
//kCAFillModeForwards//動畫結束后回到準備狀態
//kCAFillModeBackwards//動畫結束后保持最后狀態
//kCAFillModeBoth//動畫結束后回到準備狀態,并保持最后狀態
//kCAFillModeRemoved//執行完成移除動畫
[animation setFillMode:kCAFillModeBoth];
//將動畫添加到layer,添加到圖層開始執行動畫,
//注意:key值的設置與否會影響動畫的效果
//如果不設置key值每次執行都會創建一個動畫,然后創建的動畫會疊加在圖層上
//如果設置key值,系統執行這個動畫時會先檢查這個動畫有沒有被創建,如果沒有的話就創建一個,如果有的話就重新從頭開始執行這個動畫
//你可以通過key值獲取或者刪除一個動畫:
//[self.demoView.layer animationForKey:@""];
//[self.demoView.layer removeAnimationForKey:@""]
[self.demoView.layer addAnimation:animation forKey:@"baseanimation"];
}
/**
- 動畫開始和動畫結束時 self.demoView.center 是一直不變的,說明動畫并沒有改變視圖本身的位置
*/
- (void)animationDidStart:(CAAnimation *)anim{
NSLog(@"動畫開始------:%@", NSStringFromCGPoint(self.demoView.center));
}
- (void)animationDidStop:(CAAnimation )anim finished:(BOOL)flag{
NSLog(@"動畫結束------:%@", NSStringFromCGPoint(self.demoView.center));
}</code></pre>
CASpringAnimation彈性動畫
CASpringAnimation的屬性(iOS9新加)
//理解下面的屬性的時候可以結合現實物理現象,比如把它想象成一個彈簧上掛著一個金屬小球
//質量,振幅和質量成反比
@property CGFloat mass;
//剛度系數(勁度系數/彈性系數),剛度系數越大,形變產生的力就越大,運動越快
@property CGFloat stiffness;
//阻尼系數,阻止彈簧伸縮的系數,阻尼系數越大,停止越快,可以認為它是阻力系數
@property CGFloat damping;
//初始速率,動畫視圖的初始速度大小速率為正數時,速度方向與運動方向一致,速率為負數時,速度方向與運動方向相反.
@property CGFloat initialVelocity;
//結算時間,只讀.返回彈簧動畫到停止時的估算時間,根據當前的動畫參數估算通常彈簧動畫的時間使用結算時間比較準確
@property(readonly) CFTimeInterval settlingDuration;
下面我們寫一個demo看看效果:

spring彈性動畫.gif
以上gif的代碼為:
CASpringAnimation
spring = [CASpringAnimation animationWithKeyPath:@"position.y"];
spring.damping = 5;
spring.stiffness = 100;
spring.mass = 1;
spring.initialVelocity = 0;
spring.duration = spring.settlingDuration;
spring.fromValue = @(self.demoView1.center.y);
spring.toValue = @(self.demoView1.center.y + (btn.selected?+200:-200));
spring.fillMode = kCAFillModeForwards;
[self.demoView1.layer addAnimation:spring forKey:nil];</code></pre>
CASpringAnimation效果不錯,但是很不幸只有iOS9+系統才能使用,這就很操蛋了.以前項目有過這樣的需求,然后就自己寫了一個類似的動畫,效果在下面:

自定義彈性動畫.gif
然后上面自定義彈性動畫的代碼在這里:
#import "UIView+ShakeAnimation.h"
#import (objc/runtime.h)(因識別問題此處圓括號暫代尖括號)
typedef void (^RunAnimationBlock)();
@interface UIView ()
@property (nonatomic, copy)RunAnimationBlock block;
@end
@implementation UIView (ShakeAnimation)
-(void)startAnimationFromFrame:(CGRect)framef
toFrame:(CGRect)framet
duration:(CGFloat)duration
shakeTimes:(NSInteger)times
stretchPercent:(CGFloat)stretchPercent
completion:(void (^)(BOOL finished))completion
{
self.layer.masksToBounds = YES;
__block CGFloat perTime = duration / times;
__block CGFloat perx = (framet.origin.x - framef.origin.x) * stretchPercent / times;
__block CGFloat pery = (framet.origin.y - framef.origin.y) * stretchPercent / times;
__block CGFloat perw = (framet.size.width - framef.size.width) * stretchPercent / times;
__block CGFloat perh = (framet.size.height - framef.size.height) * stretchPercent / times;
__block UIView * tmpView = self;
__block NSInteger tmpTimes = (NSInteger)times;
__block NSInteger tmpsymbol = -1;
__weak typeof(self) weakSelf = self;
self.block = ^{
[UIView animateWithDuration:perTime animations:^{
CGFloat x = framet.origin.x + perx * tmpTimes;
CGFloat y = framet.origin.y + pery * tmpTimes;
CGFloat w = framet.size.width + perw * tmpTimes;
CGFloat h = framet.size.height + perh * tmpTimes;
CGRect rect = CGRectMake(x, y, w, h);
tmpView.frame = rect;
}completion:^(BOOL finished) {
tmpTimes = tmpTimes + tmpsymbol;
tmpTimes = - tmpTimes;
tmpsymbol = - tmpsymbol;
if (tmpTimes != 0) {
weakSelf.block();
}else{
[UIView animateWithDuration:perTime animations:^{
tmpView.frame = framet;
}completion:^(BOOL finished) {
completion(YES);
}];
}
}];
};
self.block();
}
static char RunAnimationBlockKey;
-(RunAnimationBlock)block{
return objc_getAssociatedObject(self, &RunAnimationBlockKey);
}
-(void)setBlock:(RunAnimationBlock)block{
objc_setAssociatedObject(self, &RunAnimationBlockKey, block, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end</code></pre>
調用:
[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);
}];
CAKeyframeAnimation關鍵幀動畫
CAKeyframeAnimation的屬性
//關鍵幀值數組,一組變化值
@property(nullable, copy) NSArray *values;
//關鍵幀幀路徑,優先級比values大
@property(nullable) CGPathRef path;
//每一幀對應的時間,時間可以控制速度.它和每一個幀相對應,取值為0.0-1.0,不設則每一幀時間相等.
@property(nullable, copy) NSArray *keyTimes;
//每一幀對應的時間曲線函數,也就是每一幀的運動節奏
@property(nullable, copy) NSArray *timingFunctions;
//動畫的計算模式,默認值: kCAAnimationLinear.有以下幾個值:
//kCAAnimationLinear//關鍵幀為座標點的時候,關鍵幀之間直接直線相連進行插值計算;
//kCAAnimationDiscrete//離散的,也就是沒有補間動畫
//kCAAnimationPaced//平均,keyTimes跟timeFunctions失效
//kCAAnimationCubic對關鍵幀為座標點的關鍵幀進行圓滑曲線相連后插值計算,對于曲線的形狀還可以通過tensionValues,continuityValues,biasValues來進行調整自定義,keyTimes跟timeFunctions失效
//kCAAnimationCubicPaced在kCAAnimationCubic的基礎上使得動畫運行變得均勻,就是系統時間內運動的距離相同,,keyTimes跟timeFunctions失效
@property(copy) NSString *calculationMode;
//動畫的張力,當動畫為立方計算模式的時候此屬性提供了控制插值,因為每個關鍵幀都可能有張力所以連續性會有所偏差它的范圍為[-1,1].同樣是此作用
@property(nullable, copy) NSArray *tensionValues;
//動畫的連續性值
@property(nullable, copy) NSArray *continuityValues;
//動畫的偏斜率
@property(nullable, copy) NSArray *biasValues;
//動畫沿路徑旋轉方式,默認為nil.它有兩個值:
//kCAAnimationRotateAuto//自動旋轉,
//kCAAnimationRotateAutoReverse//自動翻轉
@property(nullable, copy) NSString *rotationMode;
CAKeyframeAnimation可以做很豐富的效果,下面展示了幾種純CAKeyframeAnimation做的效果:

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

CAAnimationGroup.gif
這個是動畫是,旋轉,抖動,透明度一起作用在一起的效果
CATransition轉場動畫
//轉場類型,字符串類型參數.系統提供了四中動畫形式:
//kCATransitionFade//逐漸消失
//kCATransitionMoveIn//移進來
//kCATransitionPush//推進來
//kCATransitionReveal//揭開
//另外,除了系統給的這幾種動畫效果,我們還可以使用系統私有的動畫效果:
//@"cube",//立方體翻轉效果
//@"oglFlip",//翻轉效果
//@"suckEffect",//收縮效果,動畫方向不可控
//@"rippleEffect",//水滴波紋效果,動畫方向不可控
//@"pageCurl",//向上翻頁效果
//@"pageUnCurl",//向下翻頁效果
//@"cameralIrisHollowOpen",//攝像頭打開效果,動畫方向不可控
//@"cameraIrisHollowClose",//攝像頭關閉效果,動畫方向不可控
@property(copy) NSString *type;
//轉場方向,系統一共提供四個方向:
//kCATransitionFromRight//從右開始
//kCATransitionFromLeft//從左開始
//kCATransitionFromTop//從上開始
//kCATransitionFromBottom//從下開始
@property(nullable, copy) NSString *subtype;
//開始進度,默認0.0.如果設置0.3,那么動畫將從動畫的0.3的部分開始
@property float startProgress;
//結束進度,默認1.0.如果設置0.6,那么動畫將從動畫的0.6部分以后就會結束
@property float endProgress;
//開始進度
@property(nullable, strong) id filter;
CATransition也是繼承CAAnimation,系統默認提供了12種動畫樣式,加上4個動畫方向,除了方向不可控的四種效果外,大概一共提供了36種動畫.
另外系統還給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;
//設置代理
- (void)setAnimationDelegate:(nullable id)delegate; //設置動畫開始方法
- (void)setAnimationWillStartSelector:(nullable SEL)selector;
//設置動畫結束方法
- (void)setAnimationDidStopSelector:(nullable SEL)selector;
//設置動畫時間:default = 0.2
- (void)setAnimationDuration:(NSTimeInterval)duration;
//設置動畫延遲開始時間:default = 0.0
- (void)setAnimationDelay:(NSTimeInterval)delay;
//設置動畫延遲開始日期:default = now ([NSDate date])
- (void)setAnimationStartDate:(NSDate *)startDate;
//設置動畫運動曲線:default =UIViewAnimationCurveEaseInOut
//UIViewAnimationCurveEaseInOut,//慢進慢出
//UIViewAnimationCurveEaseIn, //慢進快出
//UIViewAnimationCurveEaseOut,//快進慢出
//UIViewAnimationCurveLinear//勻速
- (void)setAnimationCurve:(UIViewAnimationCurve)curve;
//設置重復次數: default = 0.0. May be fractional
- (void)setAnimationRepeatCount:(float)repeatCount;
//設置是否翻轉動畫: default = NO. used if repeat
- (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
//設置動畫是否從當前狀態開始:default = NO
- (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;
//設置動畫類型
- (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
//設置動畫是否有效
- (void)setAnimationsEnabled:(BOOL)enabled;
//
- (BOOL)areAnimationsEnabled;
//
- (void)performWithoutAnimation:(void (^)(void))actionsWithoutAnimation
//
- (NSTimeInterval)inheritedAnimationDuration
@end</code></pre>
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</code></pre>
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</code></pre>
以上方法比較多,找值得說的簡單說一下吧:
//單視圖轉場動畫
- (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</code></pre>
這兩個都是轉場動畫,不同的是第一個是單視圖轉場,第二個是雙視圖轉場.不過需要注意的是:單視圖轉場動畫只能用作屬性動畫做不到的轉場效果,比如屬性動畫不能給UIImageview的image賦值操作做動畫效果等.
我們可以看到以上兩個方法中都有一個共同的參數:
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);
可以看到系統給到的是一個位移枚舉,這就意味著這個枚舉可以多個值同時使用,但是怎么用呢?其實那些枚舉值可以分為三個部分.
我們分別看一下每個枚舉的意思:
第一部分:動畫效果
UIViewAnimationOptionTransitionNone//沒有效果
UIViewAnimationOptionTransitionFlipFromLeft//從左水平翻轉
UIViewAnimationOptionTransitionFlipFromRight//從右水平翻轉
UIViewAnimationOptionTransitionCurlUp//翻書上掀
UIViewAnimationOptionTransitionCurlDown//翻書下蓋UIViewAnimationOptionTransitionCrossDissolve//融合
UIViewAnimationOptionTransitionFlipFromTop//從上垂直翻轉
UIViewAnimationOptionTransitionFlipFromBottom//從下垂直翻轉
第二部分:動畫運動曲線
//開始慢,加速到中間,然后減慢到結束
UIViewAnimationOptionCurveEaseInOut
//開始慢,加速到結束
UIViewAnimationOptionCurveEaseIn
//開始快,減速到結束
UIViewAnimationOptionCurveEaseOut
//線性運動
UIViewAnimationOptionCurveLinear
第三部分:其他
//默認,跟父類作為一個整體
UIViewAnimationOptionLayoutSubviews
//設置了這個,主線程可以接收點擊事件
UIViewAnimationOptionAllowUserInteraction
//從當前狀態開始動畫,父層動畫運動期間,開始子層動畫.
UIViewAnimationOptionBeginFromCurrentState
//重復執行動畫,從開始到結束, 結束后直接跳到開始態
UIViewAnimationOptionRepeat
//反向執行動畫,結束后會再從結束態->開始態
UIViewAnimationOptionAutoreverse
//忽略繼承自父層持續時間,使用自己持續時間(如果存在)
UIViewAnimationOptionOverrideInheritedDuration
//忽略繼承自父層的線性效果,使用自己的線性效果(如果存在)
UIViewAnimationOptionOverrideInheritedCurve
//允許同一個view的多個動畫同時進行
UIViewAnimationOptionAllowAnimatedContent
//視圖切換時直接隱藏舊視圖、顯示新視圖,而不是將舊視圖從父視圖移除(僅僅適用于轉場動畫) UIViewAnimationOptionShowHideTransitionViews
//不繼承父動畫設置或動畫類型.
UIViewAnimationOptionOverrideInheritedOptions
這下可以看到,這些枚舉功能都不一樣但是可以隨意組合,但是組合的時候需要注意,同一類型的枚舉不能一起使用比如UIViewAnimationOptionCurveEaseIn和UIViewAnimationOptionCurveEaseOut
然后我們看一下轉場動畫的一些效果:
單視圖轉場

單視圖轉場.gif
雙視圖轉場

雙視圖轉場.gif
CATransition視圖轉場

CATransition.gif
動畫效果太多,gif錄不了太大,效果沒有一一展示.然后代碼再這里: demo-轉場動畫
除了3D變換動畫,和繪圖相關的動畫,基本上我們常用到的動畫都在這里了.另外感謝這些參考博客的博主~
來自:http://www.cocoachina.com/ios/20170315/18890.html