在AppStore中的應用越來越重視動畫效果的使用,一個良好動畫效果可以讓兩個狀態之間平滑地過度,也可以利用動畫吸引住用戶的眼球,在UIView類中共有三個類目(Category)用於實現動畫功能,分為UIViewAnimation、UIViewAnimationWithBlocks以及UIViewKeyframeAnimations,他們是Apple對核心動畫(Core Animation)的封裝,可以讓我們不進行任何繪畫等復雜操作的前提下實現大部分動畫需求
UIView類中提供的動畫功能,允許我們實現如下動畫需求
動態修改”可動畫屬性”在介紹UIView動畫的過程中,我們會使用一個UIImageView圖片為例,對各動畫效果進行演示
@property (nonatomic, strong) UIImageView *demoImageView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.demoImageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, [[UIScreen mainScreen] bounds].size.width-40, [[UIScreen mainScreen] bounds].size.height-40)];
self.demoImageView.image = [UIImage imageNamed:@"old"];
[self.view addSubview:self.demoImageView];
}
Apple自iOS2開始提供了若干UIView的類方法來實現動畫功能,Apple建議從iOS4系統開始盡量使用Block方式來實現動畫功能,因此我們以後在開發中應該遵從Apple的建議使用Block方式來實現動畫功能,但是學習本部分對未來學好Block動畫有很好的鋪墊作用,因此本文在這裡會對系統提供的方法進行詳盡地介紹
在iOS4之前,我們需要使用動畫塊(begin/commit animation block)來進行動畫,一個完整的動畫塊由以下四部分組成
動畫塊開始標識 配置動畫選擇項 修改可動畫屬性 動畫塊結束標識標識動畫塊的開始,該方法是告訴系統將要執行一個或多個動畫,如果通過setAnimationWillStartSelector:或者setAnimationDidStopSelector:方法設置了代理回調方法,便可以在回調方法中收到該方法中的兩個參數animationID(動畫標志)和context(上下文,一般為nil)
// 格式
+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;
// 樣例
[UIView beginAnimations:@"demo" context:nil];
標識動畫塊的結束,同時安排動畫執行
// 格式
+ (void)commitAnimations;
// 樣例
[UIView commitAnimations];
設置動畫代理對象,以便在動畫開始和結束時收到系統回調
// 格式
+ (void)setAnimationDelegate:(nullable id)delegate;
// 樣例
[UIView setAnimationDelegate:self];
設置動畫將要開始時調用代理對象的方法
// 格式
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;
// 樣例
[UIView setAnimationWillStartSelector:@selector(animationWillStart:context:)];
注1: 當動畫當前不可用時,該方法不會被調用
注2: 當不設置該方法時,系統默認會調用- (void)animationWillStart:(NSString )animationID context:(void )context
設置動畫已經結束後調用代理對象的方法
// 格式
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;
// 樣例
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
注1: 當動畫當前不可用時,該方法依然會被調用
注2: 當不設置該方法時,系統默認會調用- (void)animationDidStop:(NSString )animationID finished:(NSNumber )finished context:(void *)context
設置動畫持續時長,默認0.2s
// 格式
+ (void)setAnimationDuration:(NSTimeInterval)duration;
// 樣例
[UIView setAnimationDuration:0.2f];
注: 該方法必須在修改”可變化屬性”之前調用
設置延時動畫時長,默認0.0s
// 格式
+ (void)setAnimationDelay:(NSTimeInterval)delay;
// 樣例
[UIView setAnimationDelay:0.0f];
注: 該方法必須在修改”可變化屬性”之前調用
設置動畫開始時間,默認當前時間
// 格式
+ (void)setAnimationStartDate:(NSDate *)startDate;
// 樣例
[UIView setAnimationStartDate:[NSDate date]];
注1: 該方法必須在修改”可變化屬性”之前調用
注2: 不要在Block動畫中調用該方法
注3: 該方法設置後整個動畫即不生效,作者嘗試過如下四種方式,結果都不生效
[UIView setAnimationStartDate:[NSDate date]];
[UIView setAnimationStartDate:[NSDate dateWithTimeIntervalSinceReferenceDate:CFAbsoluteTimeGetCurrent()]];
[UIView setAnimationStartDate:[NSDate dateWithTimeIntervalSinceNow:3]];
[UIView setAnimationStartDate:[NSDate dateWithTimeIntervalSinceReferenceDate:CFAbsoluteTimeGetCurrent()+3]];
時間函數即動畫進行速度隨著時間的變化曲線,系統采用一個枚舉類型來保存
/**
typedef NS_ENUM(NSInteger, UIViewAnimationCurve)
{
UIViewAnimationCurveEaseInOut // 默認,淡入淡出,先慢後快再慢
UIViewAnimationCurveEaseIn // 淡入,先慢後快
UIViewAnimationCurveEaseOut // 淡出,先快後慢
UIViewAnimationCurveLinear // 線性
};
*/
// 格式
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;
// 樣例
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
注: 該方法必須在修改”可變化屬性”之前調用
設置動畫重復次數,重復次數可以是小數,小數部分會做相應比例的動畫,然後直接變化到動畫結束位置
// 格式
+ (void)setAnimationRepeatCount:(float)repeatCount;
// 樣例
[UIView setAnimationRepeatCount:2.5f];
注: 該方法必須在修改”可變化屬性”之前調用
設置是否反向動畫,默認為NO,如果設置為YES,動畫向前做完會做一次反向動畫,那麼一正一反算作一次repeatCount,動畫所用時長會加倍
// 格式
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
// 樣例
[UIView setAnimationRepeatAutoreverses:YES];
注1: 該方法必須在修改”可變化屬性”之前調用
注2: 因為當動畫結束後一定會定格在動畫塊中設置的新位置上,為了不在最後產生一次不和諧的跳動,可以將repeatCount設置成0.5次即可
該方法用於處理當舊動畫正在運行時開始一個新的動畫,是否從舊動畫的當前狀態開始新動畫,默認為NO
當設置為NO時,舊動畫的結束狀態會被作為新動畫的初始狀態,且舊動畫會在新動畫開始的時候立刻結束動畫 當設置為YES時,舊動畫的當前狀態會被作為新動畫的初始狀態
// 格式
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;
// 樣例
[UIView setAnimationBeginsFromCurrentState:NO];
設置轉場效果,該方法有如下三個參數
參數1: 轉場動畫方向,系統采用一個枚舉類型來保存 參數2: 參與轉場動畫的視圖(轉場動畫效果發生在該視圖上) 參數3: 如果設置為YES,則視圖在開始和結束時分別渲染一次,在動畫過程中不可以更新視圖(這樣性能好),如果設置為NO,則視圖每一幀都會渲染,在動畫過程中可以實時更新視圖(這樣能力強)
/**
typedef NS_ENUM(NSInteger, UIViewAnimationTransition)
{
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown
};
*/
// 格式
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
// 樣例
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:NO];
注: 該方法每個動畫塊中只可調用一次
設置是否動畫可用,默認為YES,如果設置為NO,則沒有動畫效果,屬性變化立即生效
// 格式
+ (void)setAnimationsEnabled:(BOOL)enabled;
// 樣例
[UIView setAnimationsEnabled:YES];
注: 該設置只影響在這句代碼之後設置的屬性變化
返回一個BOOL值標識是否動畫可用
// 格式
+ (BOOL)areAnimationsEnabled;
// 樣例
[UIView areAnimationsEnabled];
Apple在iOS7中新增加了一個簡單的封裝,該方法會先檢查動畫當前是否為可用狀態,然後設置動畫為不可用狀態,執行Block中的代碼,最後重新恢復動畫為原來狀態
// 格式
+ (void)performWithoutAnimation:(void (^)(void))actionsWithoutAnimation;
// 樣例
[UIView performWithoutAnimation:^{
self.demoImageView.alpha = 0.4;
}];
動畫塊的嵌套使用,是指在commit提交前一個動畫之前再次調用begin方法創建一個新的動畫,該新動畫可以根據需求指定與外層動畫不同的”動畫持續時長”“時間函數”等動畫選擇項,當調用commit提交一個動畫時,如果當前動畫塊是在最外層,該方法會開始做動畫,如果當前動畫塊嵌套在另一個動畫塊的裡面,該方法會等待外層的動畫塊提交,直到最外層動畫塊提交之後一起做動畫,動畫是在單獨的線程運行,這樣多個動畫便可以一個一個地執行起來
// 以"嵌套動畫的外層歷時5s將視圖透明度修改為0.2,嵌套動畫的內層不繼承外層動畫的持續時長,將視圖大小縮小一半,期間重復2.5次"為例,代碼如下
[UIView beginAnimations:@"parent" context:nil];
[UIView setAnimationDuration:5.0f];
self.demoImageView.alpha = 0.2f;
[UIView beginAnimations:@"demo2" context:nil];
[UIView setAnimationDuration:1.0f];
[UIView setAnimationRepeatCount:2.5f];
[UIView setAnimationRepeatAutoreverses:YES];
self.demoImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
[UIView commitAnimations];
[UIView commitAnimations];
例子一
// 以"將視圖大小縮小一半,並做反向動畫,最後平滑地停留在預定位置"為例,代碼如下
[UIView beginAnimations:@"demo" context:nil];
[UIView setAnimationDuration:1.0f];
[UIView setAnimationRepeatCount:2.5];
[UIView setAnimationRepeatAutoreverses:YES];
self.demoImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
[UIView commitAnimations];
例子二
// 以"從左側翻轉轉場動畫,且將視圖大小縮小一半(動畫效果發生在該視圖上)"為例,代碼如下
[UIView beginAnimations:@"demo" context:nil];
[UIView setAnimationDuration:1.0f];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.demoImageView cache:YES];
self.demoImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
[UIView commitAnimations];
Apple從iOS4開始加入了Block功能,UIView的普通動畫方法全面增加了對Block的支持,自此我們便可以非常方便地使用動畫功能,推薦使用
/**
* 屬性動畫
*
* @param duration 動畫持續時長
* @param delay 延時動畫時長
* @param options 動畫選擇項
* @param animations 動畫Block
* @param completion 動畫執行完執行的Block
*
* @return 無返回值
*/
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
// 以"將視圖大小縮小一半,動畫結束後恢復"為例,代碼如下
[UIView animateWithDuration:3.0f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.demoImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
} completion:^(BOOL finished) {
if (finished)
{
self.demoView.transform = CGAffineTransformIdentity;
}
}];
上述Block動畫共有5個參數,使用起來需要設置的內容比較多,系統為我們提供了兩個相對簡單的Block動畫以用於簡單動畫
// delay = 0.0,options = 0的屬性動畫
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
// delay = 0.0,options = 0,completion = NULL的屬性動畫
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;
Apple從iOS7開始在系統中大量使用SpringAnimation,該動畫由於前期速度很快,可以給用戶一種干淨利落的感覺,所以推薦大家使用以與系統動畫接軌
/**
* SpringAnimation(彈性動畫)
*
* @param duration 動畫持續時長
* @param delay 延時動畫時長
* @param dampingRatio 當dampingRatio設置為1時,動畫會毫無震蕩感地平穩地運動到最終狀態,如果dampingRatio的值少於1,值越小在最終狀態上震蕩效果會越明顯
* @param velocity 初始速度,數值越大一開始移動速度越快(注: 初始速度取值較高而時間取值較短時,也會產生震蕩效果)
* @param options 動畫選擇項
* @param animations 動畫Block
* @param completion 動畫執行完執行的Block
*
* @return 無返回值
*/
+ (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;
// 以"將視圖大小縮小一半,動畫結束後恢復"為例,代碼如下
[UIView animateWithDuration:3.0f delay:0.0f usingSpringWithDamping:0.7f initialSpringVelocity:5.0f options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.demoImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
} completion:^(BOOL finished) {
if (finished)
{
self.demoView.transform = CGAffineTransformIdentity;
}
}];
Apple從iOS7開始加入了一個方法,允許我們執行系統動畫,且可以並行地執行附加動畫
/**
* 在一個或多個視圖上執行系統動畫
*
* @param animation 系統動畫,暫時只有UISystemAnimationDelete一個
* @param views 執行動畫的views數組
* @param options 動畫選擇項
* @param parallelAnimations 並行附加動畫Block
* @param completion 動畫執行完執行的Block
*
* @return 無返回值
*/
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion;
// 以"執行系統刪除動畫"為例,代碼如下
[UIView performSystemAnimation:UISystemAnimationDelete onViews:@[self.demoImageView] options:UIViewAnimationOptionCurveEaseInOut animations:^{
// do something....
} completion:^(BOOL finished) {
if (finished)
{
// do something....
}
}];
注: 附加動畫不要修改正在被系統動畫修改的屬性
Apple為我們提供了兩個方法用於進行轉場動畫,為我們解決兩個動畫需求
修改已存在視圖的子視圖(也可以修改自身)
/**
* TransitionAnimation(轉場動畫)
*
* @param view 參與轉場動畫的視圖(轉場動畫效果發生在該視圖上)
* @param duration 動畫持續時長
* @param options 動畫選擇項
* @param animations 動畫Block
* @param completion 動畫執行完執行的Block
*
* @return 無返回值
*/
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
// 以"父視圖從左側翻轉轉場動畫,且將子視圖大小縮小一半,動畫結束後恢復"為例,代碼如下
[UIView transitionWithView:self.view duration:3.0f options:UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionAllowAnimatedContent animations:^{
self.demoImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
} completion:^(BOOL finished) {
if (finished)
{
self.demoImageView.transform = CGAffineTransformIdentity;
}
}];
在視圖層級中用一個視圖替換另一個視圖注: 該轉場動畫作用於view上
/**
* TransitionAnimation(轉場動畫)
*
* @param fromView 參與轉場動畫的視圖(被移除視圖)
* @param toView 參與轉場動畫的視圖(被添加視圖)
* @param duration 動畫持續時長
* @param options 動畫選擇項
* @param completion 動畫執行完執行的Block
*
* @return 無返回值
*/
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion;
// 以"從左側翻轉轉場動畫,將原視圖移除,添加新視圖進來"為例,代碼如下
UIImageView *toImageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, [[UIScreen mainScreen] bounds].size.width-40, [[UIScreen mainScreen] bounds].size.height-40)];
toImageView.image = [UIImage imageNamed:@"new"];
[UIView transitionFromView:self.demoImageView toView:toImageView duration:3.0f options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) {
if (finished)
{
NSLog(@"TransitionAnimation finished");
}
}];
注: 該轉場動畫作用於fromView的父視圖上,相當於將toView添加到fromView的父視圖上,並將fromView從父視圖上移除
Block動畫的嵌套使用,是指在Block動畫的animations中再創建一個新的Block動畫,該新動畫可以根據需求指定與外層動畫不同的”動畫選擇項”,新動畫會繼承外層動畫的”動畫持續時長”和”時間函數”,但是一些”動畫選擇項”不會繼承(在動畫選擇項中提供了兩個用於嵌套動畫的選擇項,UIViewAnimationOptionOverrideInheritedDuration代表忽略嵌套動畫中外層動畫的時長設置,UIViewAnimationOptionOverrideInheritedCurve代表忽略嵌套動畫中外層動畫的時間函數設置)
// 以"嵌套動畫的外層歷時5s將視圖透明度修改為0.2,嵌套動畫的內層不繼承外層動畫的持續時長,將視圖大小縮小一半,期間重復2.5次"為例,代碼如下
[UIView animateWithDuration:5.0f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.demoImageView.alpha = 0.2f;
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionOverrideInheritedDuration | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{
[UIView setAnimationRepeatCount:2.5];
self.demoImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
} completion:nil];
} completion:nil];
注: 如果不使用UIViewAnimationOptionOverrideInheritedDuration,嵌套動畫的內層會直接繼承外層的持續時長
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions)
{
// 通用設置(可同時設置多個)
UIViewAnimationOptionLayoutSubviews = 1 << 0, // 動畫過程中,子視圖隨著一起動畫
UIViewAnimationOptionAllowUserInteraction = 1 << 1, // 動畫過程中,允許用戶交互
UIViewAnimationOptionBeginFromCurrentState = 1 << 2, // 是否從舊動畫的當前狀態開始新動畫,參考UIView的+(void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;方法
UIViewAnimationOptionRepeat = 1 << 3, // 無限次數重復動畫
UIViewAnimationOptionAutoreverse = 1 << 4, // 是否開啟反向動畫,參考UIView的+(void)setAnimationRepeatAutoreverses:方法(BOOL)repeatAutoreverses;方法
UIViewAnimationOptionOverrideInheritedDuration = 1 << 5, // 忽略嵌套動畫中外層動畫的時長設置(只適用於嵌套動畫)
UIViewAnimationOptionOverrideInheritedCurve = 1 << 6, // 忽略嵌套動畫中外層動畫的時間函數設置(只適用於嵌套動畫)
UIViewAnimationOptionAllowAnimatedContent = 1 << 7, // 視圖每一幀都會渲染,在動畫過程中可以實時更新視圖(只適用於轉場動畫)
UIViewAnimationOptionShowHideTransitionViews = 1 << 8, // 視圖切換時直接隱藏舊視圖並顯示新視圖,而不是將舊視圖從父視圖移除並添加新視圖(只適用於轉場動畫)
UIViewAnimationOptionOverrideInheritedOptions = 1 << 9, // 不繼承動畫選擇項(只適用於嵌套動畫)
// 時間函數控制(只可同時設置一項),參考UIView的+(void)setAnimationCurve:(UIViewAnimationCurve)curve;方法
UIViewAnimationOptionCurveEaseInOut = 0 << 16, // 默認,淡入淡出,先慢後快再慢
UIViewAnimationOptionCurveEaseIn = 1 << 16, // 淡入,先慢後快
UIViewAnimationOptionCurveEaseOut = 2 << 16, // 淡出,先快後慢
UIViewAnimationOptionCurveLinear = 3 << 16, // 線性
// 轉場動畫方向(只適用於轉場動畫,只可同時設置一項),參考UIView的+(void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;方法
UIViewAnimationOptionTransitionNone = 0 << 20, // 默認,無效果
UIViewAnimationOptionTransitionFlipFromLeft = 1 << 20, // 從左側翻轉
UIViewAnimationOptionTransitionFlipFromRight = 2 << 20, // 從右側翻轉
UIViewAnimationOptionTransitionCurlUp = 3 << 20, // 向後翻頁
UIViewAnimationOptionTransitionCurlDown = 4 << 20, // 向前翻頁
UIViewAnimationOptionTransitionCrossDissolve = 5 << 20, // 舊視圖溶解顯示新視圖
UIViewAnimationOptionTransitionFlipFromTop = 6 << 20, // 從上方翻轉
UIViewAnimationOptionTransitionFlipFromBottom = 7 << 20, // 從下方翻轉
}
Apple從iOS7開始加入了關鍵幀動畫,可以通過提供一個動畫在多個關鍵幀處的屬性實現一系列動畫效果,兩個關鍵幀中間會有系統自動加入補間動畫
/**
* KeyframeAnimation(關鍵幀動畫)
*
* @param duration 動畫持續時長
* @param delay 延時動畫時長
* @param options 關鍵幀動畫選擇項
* @param animations 動畫Block
* @param completion 動畫執行完執行的Block
*
* @return 無返回值
*/
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
/**
* 添加關鍵幀
*
* @param frameStartTime 幀動畫相對開始時間,取值為0~1
* @param frameDuration 幀動畫相對持續時長,取值為0~1
* @param animations 幀動畫Block
*
* @return 無返回值
*/
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations;
// 以"將視圖大小縮小一半,再順時針旋轉90度,再放大2倍,再逆時針旋轉90度恢復原樣"為例,代碼如下
[UIView animateKeyframesWithDuration:3.0f delay:0.0f options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.25f animations:^{
self.demoImageView.transform = CGAffineTransformScale(self.demoImageView.transform, 0.5, 0.5);
}];
[UIView addKeyframeWithRelativeStartTime:0.25f relativeDuration:0.25f animations:^{
self.demoImageView.transform = CGAffineTransformRotate(self.demoImageView.transform, M_PI * 0.5);
}];
[UIView addKeyframeWithRelativeStartTime:0.5f relativeDuration:0.25f animations:^{
self.demoImageView.transform = CGAffineTransformScale(self.demoImageView.transform, 2, 2);
}];
[UIView addKeyframeWithRelativeStartTime:0.75f relativeDuration:0.25f animations:^{
self.demoImageView.transform = CGAffineTransformRotate(self.demoImageView.transform, -M_PI * 0.5);
}];
} completion:^(BOOL finished) {
if (finished)
{
NSLog(@"TransitionAnimation finished");
}
else
{
NSLog(@"在動畫執行過程中再次被觸發動畫,會調用這裡後重新開始動畫");
}
}];
注: 關鍵幀動畫有兩種形式,UIView只支持屬性關鍵幀動畫,暫不支持路徑關鍵幀動畫
typedef NS_OPTIONS(NSUInteger, UIViewKeyframeAnimationOptions)
{
// 通用設置(可同時設置多個)
UIViewKeyframeAnimationOptionLayoutSubviews = UIViewAnimationOptionLayoutSubviews, // 動畫過程中,子視圖隨著一起動畫
UIViewKeyframeAnimationOptionAllowUserInteraction = UIViewAnimationOptionAllowUserInteraction, // 動畫過程中,允許用戶交互
UIViewKeyframeAnimationOptionBeginFromCurrentState = UIViewAnimationOptionBeginFromCurrentState, // 是否從舊動畫的當前狀態開始新動畫
UIViewKeyframeAnimationOptionRepeat = UIViewAnimationOptionRepeat, // 無限次數重復動畫
UIViewKeyframeAnimationOptionAutoreverse = UIViewAnimationOptionAutoreverse, // 是否開啟反向動畫
UIViewKeyframeAnimationOptionOverrideInheritedDuration = UIViewAnimationOptionOverrideInheritedDuration, // 忽略嵌套動畫中外層動畫的時長設置(只適用於嵌套動畫)
UIViewKeyframeAnimationOptionOverrideInheritedOptions = UIViewAnimationOptionOverrideInheritedOptions, // 忽略嵌套動畫中外層動畫的時間函數設置(只適用於嵌套動畫)
// 設置兩個關鍵幀之間的動畫模式(可理解為補間動畫模式)(只可同時設置一項)
UIViewKeyframeAnimationOptionCalculationModeLinear = 0 << 10, // 默認,線性運算模式(勻速補間動畫)
UIViewKeyframeAnimationOptionCalculationModeDiscrete = 1 << 10, // 離散運算模式(無補間動畫)
UIViewKeyframeAnimationOptionCalculationModePaced = 2 << 10, // 均勻運算模式
UIViewKeyframeAnimationOptionCalculationModeCubic = 3 << 10, // 平滑運算模式
UIViewKeyframeAnimationOptionCalculationModeCubicPaced = 4 << 10 // 平滑均勻運算模式
}