版本記錄
| 版本號 | 時間 |
|---|---|
| V1.0 | 2017.09.24 |
前言
app中好的炫的動畫可以讓用戶耳目一新,為產(chǎn)品增色不少,關(guān)于動畫的實現(xiàn)我們可以用基本動畫、關(guān)鍵幀動畫、序列幀動畫以及基于CoreGraphic的動畫等等,接下來這幾篇我就介紹下我可以想到的幾種動畫繪制方法。具體Demo示例已開源到Github —— 刀客傳奇,感興趣的可以看我寫的另外幾篇。
1. 實現(xiàn)動畫方式深度解析(一) —— 播放GIF動畫(一)
2. 實現(xiàn)動畫方式深度解析(二) —— 播放GIF動畫之框架FLAnimatedImage的使用(二)
3. 實現(xiàn)動畫方式深度解析(三) —— 播放序列幀動畫(一)
4. 實現(xiàn)動畫方式深度解析(四) —— QuartzCore框架(一)
5. 實現(xiàn)動畫方式深度解析(五) —— QuartzCore框架之CoreAnimation(二)
6. 實現(xiàn)動畫方式深度解析(六) —— Core Animation Basics(三)
7. 實現(xiàn)動畫方式深度解析(七) —— Core Animation之Setting Up Layer Objects(四)
8. 實現(xiàn)動畫方式深度解析(八) —— Core Animation之動畫層內(nèi)容 (五)
9. 實現(xiàn)動畫方式深度解析(九) —— Core Animation之構(gòu)建圖層層級 (六)
10. 實現(xiàn)動畫方式深度解析(十) —— Core Animation之高級動畫技巧 (七)
11. 實現(xiàn)動畫方式深度解析(十一) —— Core Animation之更改圖層的默認(rèn)行為(八)
12. 實現(xiàn)動畫方式深度解析(十二) —— Core Animation之提高動畫的性能(九)
13. 實現(xiàn)動畫方式深度解析(十三) —— Core Animation之圖層樣式屬性動畫(十)
14. 實現(xiàn)動畫方式深度解析(十四) —— Core Animation之 KVC 擴展(十一)
15. 實現(xiàn)動畫方式深度解析(十五) —— Core Animation之可動畫屬性 (十二)
16. 實現(xiàn)動畫方式深度解析(十六) —— Core Animation之CABasicAnimation動畫示例 (十三)
17. 實現(xiàn)動畫方式深度解析(十七) —— Core Animation之CAKeyframeAnimation動畫示例 (十四)
UIView動畫
UIView動畫也是系統(tǒng)提供的一種動畫實現(xiàn)方式,這種方式是實現(xiàn)很簡單。UIView動畫可以看做是對Core Animation的封裝。
UIView可以進(jìn)行動畫屬性如下:
frameboundscentertransformalphabackgroundColorcontentStretch
下面我們看一下UIView提供了有關(guān)動畫的接口。
@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; // starts up any animations when the top level animation is commited
// no getters. if called outside animation block, these setters have no effect.
+ (void)setAnimationDelegate:(nullable id)delegate; // default = nil
+ (void)setAnimationWillStartSelector:(nullable SEL)selector; // default = NULL. -animationWillStart:(NSString *)animationID context:(void *)context
+ (void)setAnimationDidStopSelector:(nullable SEL)selector; // default = NULL. -animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
+ (void)setAnimationDuration:(NSTimeInterval)duration; // default = 0.2
+ (void)setAnimationDelay:(NSTimeInterval)delay; // default = 0.0
+ (void)setAnimationStartDate:(NSDate *)startDate; // default = now ([NSDate date])
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve; // default = UIViewAnimationCurveEaseInOut
+ (void)setAnimationRepeatCount:(float)repeatCount; // default = 0.0. May be fractional
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses; // default = NO. used if repeat count is non-zero
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState; // default = NO. If YES, the current view position is always used for new animations -- allowing animations to "pile up" on each other. Otherwise, the last end state is used for the animation (the default).
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache; // current limitation - only one per begin/commit block
+ (void)setAnimationsEnabled:(BOOL)enabled; // ignore any attribute changes while set.
#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) BOOL areAnimationsEnabled;
#else
+ (BOOL)areAnimationsEnabled;
#endif
+ (void)performWithoutAnimation:(void (NS_NOESCAPE ^)(void))actionsWithoutAnimation NS_AVAILABLE_IOS(7_0);
#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) NSTimeInterval inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#else
+ (NSTimeInterval)inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#endif
@end
@interface UIView(UIViewAnimationWithBlocks)
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL
/* Performs `animations` using a timing curve described by the motion of a spring. When `dampingRatio` is 1, the animation will smoothly decelerate to its final model values without oscillating. Damping ratios less than 1 will oscillate more and more before coming to a complete stop. You can use the initial spring velocity to specify how fast the object at the end of the simulated spring was moving before it was attached. It's a unit coordinate system, where 1 is defined as travelling the total animation distance in a second. So if you're changing an object's position by 200pt in this animation, and you want the animation to behave as if the object was moving at 100pt/s before the animation started, you'd pass 0.5. You'll typically want to pass 0 for the velocity. */
+ (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 NS_AVAILABLE_IOS(7_0);
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview
/* Performs the requested system-provided animation on one or more views. Specify addtional animations in the parallelAnimations block. These additional animations will run alongside the system animation with the same timing and duration that the system animation defines/inherits. Additional animations should not modify properties of the view on which the system animation is being performed. Not all system animations honor all available options.
*/
+ (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
@interface UIView (UIViewKeyframeAnimations)
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations NS_AVAILABLE_IOS(7_0); // start time and duration are values between 0.0 and 1.0 specifying time and duration relative to the overall time of the keyframe animation
@end
UIView 動畫幾個重要接口
下面我們就看一下幾個重要的接口。
1. 動畫開始
+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;
// additional context info passed to will start/did stop selectors. begin/commit can be nested
2. 結(jié)束動畫標(biāo)記
+ (void)commitAnimations;
3. 設(shè)置動畫時間
+ (void)setAnimationDuration:(NSTimeInterval)duration;
4. 設(shè)置動畫代理
+ (void)setAnimationDelegate:(nullable id)delegate;
5. 設(shè)置動畫將開始時代理對象執(zhí)行的SEL
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;
6. 設(shè)置動畫結(jié)束時代理對象執(zhí)行的SEL
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;
7. 設(shè)置動畫延遲執(zhí)行的時間
+ (void)setAnimationDelay:(NSTimeInterval)delay;
8. 設(shè)置動畫的重復(fù)次數(shù)
+ (void)setAnimationRepeatCount:(float)repeatCount;
9. 設(shè)置動畫的曲線
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;
這里有一個枚舉值,如下所示:
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
UIViewAnimationCurveEaseInOut, // slow at beginning and end
UIViewAnimationCurveEaseIn, // slow at beginning
UIViewAnimationCurveEaseOut, // slow at end
UIViewAnimationCurveLinear,
};
10. 設(shè)置是否從當(dāng)前狀態(tài)開始播放動畫
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;
// default = NO. If YES, the current view position is always used for new animations -- allowing animations to "pile up" on each other. Otherwise, the last end state is used for the animation (the default).
假設(shè)上一個動畫正在播放,且尚未播放完畢,我們將要進(jìn)行一個新的動畫:
- 當(dāng)為YES時:動畫將從上一個動畫所在的狀態(tài)開始播放
- 當(dāng)為NO時:動畫將從上一個動畫所指定的最終狀態(tài)開始播放(此時上一個動畫馬上結(jié)束)。
11. 設(shè)置動畫是否繼續(xù)執(zhí)行相反的動畫
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
// default = NO. used if repeat count is non-zero
12. 是否禁用動畫效果
對象屬性依然會被改變,只是沒有動畫效果。
+ (void)setAnimationsEnabled:(BOOL)enabled;
13. 設(shè)置視圖的過渡效果
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
// current limitation - only one per begin/commit block
這里有一個枚舉UIViewAnimationTransition,如下所示:
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
14. block動畫
有關(guān)UIView的block動畫,全部在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 NS_AVAILABLE_IOS(4_0);
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL
/* Performs `animations` using a timing curve described by the motion of a spring. When `dampingRatio` is 1, the animation will smoothly decelerate to its final model values without oscillating. Damping ratios less than 1 will oscillate more and more before coming to a complete stop. You can use the initial spring velocity to specify how fast the object at the end of the simulated spring was moving before it was attached. It's a unit coordinate system, where 1 is defined as travelling the total animation distance in a second. So if you're changing an object's position by 200pt in this animation, and you want the animation to behave as if the object was moving at 100pt/s before the animation started, you'd pass 0.5. You'll typically want to pass 0 for the velocity. */
+ (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 NS_AVAILABLE_IOS(7_0);
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview
/* Performs the requested system-provided animation on one or more views. Specify addtional animations in the parallelAnimations block. These additional animations will run alongside the system animation with the same timing and duration that the system animation defines/inherits. Additional animations should not modify properties of the view on which the system animation is being performed. Not all system animations honor all available options.
*/
+ (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 動畫簡單示例
下面我們就看一下UIView動畫實現(xiàn)的簡單示例。
1. 簡單動畫
我們先看一下簡單的動畫示例。
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIView *animationView;
@end
@implementation ViewController
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
//UI
[self setupUI];
//UIView動畫
[self demoPropertyUIViewAnimation];
}
#pragma mark - Object Private Function
- (void)demoPropertyUIViewAnimation
{
[UIView beginAnimations:@"animation" context:nil];
[UIView setAnimationDuration:3.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationWillStartSelector:@selector(startAnimation)];
[UIView setAnimationDidStopSelector:@selector(stopAnimation)];
[UIView setAnimationRepeatCount:10];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
self.animationView.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
[UIView commitAnimations];
}
- (void)setupUI
{
self.view.backgroundColor = [UIColor lightGrayColor];
self.animationView = [[UIView alloc] initWithFrame:CGRectMake(250.0, 250.0, 200.0, 200.0)];
[self.view addSubview:self.animationView];
self.animationView.backgroundColor = [UIColor redColor];
}
#pragma mark - Action && Notification
- (void)startAnimation
{
NSLog(@"開始動畫");
}
- (void)stopAnimation
{
NSLog(@"停止動畫");
}
@end
下面我們看一下輸出以及動畫效果。
2017-09-24 20:22:24.254 JJUIViewAnimation_demo9[3301:274498] 開始動畫
2017-09-24 20:22:54.252 JJUIViewAnimation_demo9[3301:274498] 停止動畫

2. block動畫
ios 4.0以后出現(xiàn)的block動畫,這種動畫也是我們工程中常用的動畫形式。
- 最簡潔的Block動畫:包含時間和動畫
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0);
// delay = 0.0, options = 0, completion = NULL
- 帶有動畫完成回調(diào)的block動畫
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
// delay = 0.0, options = 0
- 帶有延遲時間和過度效果的動畫
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
這里有一個枚舉值UIViewAnimationOptions,它就是描述過度效果的枚舉值。
UIViewAnimationOptionLayoutSubviews //進(jìn)行動畫時布局子控件
UIViewAnimationOptionAllowUserInteraction //進(jìn)行動畫時允許用戶交互
UIViewAnimationOptionBeginFromCurrentState //從當(dāng)前狀態(tài)開始動畫
UIViewAnimationOptionRepeat //無限重復(fù)執(zhí)行動畫
UIViewAnimationOptionAutoreverse //執(zhí)行動畫回路
UIViewAnimationOptionOverrideInheritedDuration //忽略嵌套動畫的執(zhí)行時間設(shè)置
UIViewAnimationOptionOverrideInheritedCurve //忽略嵌套動畫的曲線設(shè)置
UIViewAnimationOptionAllowAnimatedContent //轉(zhuǎn)場:進(jìn)行動畫時重繪視圖
UIViewAnimationOptionShowHideTransitionViews //轉(zhuǎn)場:移除(添加和移除圖層的)動畫效果
UIViewAnimationOptionOverrideInheritedOptions //不繼承父動畫設(shè)置
UIViewAnimationOptionCurveEaseInOut //時間曲線,慢進(jìn)慢出(默認(rèn)值)
UIViewAnimationOptionCurveEaseIn //時間曲線,慢進(jìn)
UIViewAnimationOptionCurveEaseOut //時間曲線,慢出
UIViewAnimationOptionCurveLinear //時間曲線,勻速
UIViewAnimationOptionTransitionNone //轉(zhuǎn)場,不使用動畫
UIViewAnimationOptionTransitionFlipFromLeft //轉(zhuǎn)場,從左向右旋轉(zhuǎn)翻頁
UIViewAnimationOptionTransitionFlipFromRight //轉(zhuǎn)場,從右向左旋轉(zhuǎn)翻頁
UIViewAnimationOptionTransitionCurlUp //轉(zhuǎn)場,下往上卷曲翻頁
UIViewAnimationOptionTransitionCurlDown //轉(zhuǎn)場,從上往下卷曲翻頁
UIViewAnimationOptionTransitionCrossDissolve //轉(zhuǎn)場,交叉消失和出現(xiàn)
UIViewAnimationOptionTransitionFlipFromTop //轉(zhuǎn)場,從上向下旋轉(zhuǎn)翻頁
UIViewAnimationOptionTransitionFlipFromBottom //轉(zhuǎn)場,從下向上旋轉(zhuǎn)翻頁
下面我們還是先看一下示例代碼。
- (void)demoBlockUIViewAnimation
{
self.animationView.frame = CGRectMake(50.0, 250.0, 200.0, 200.0);
[UIView animateWithDuration:3.0 animations:^{
self.animationView.backgroundColor = [UIColor blueColor];
} completion:^(BOOL finished) {
NSLog(@"動畫完成了");
}];
}
上面就是一個很簡單的示例,非常簡單,下面看一下效果。

3. 轉(zhuǎn)場動畫
下面直接看代碼。
- (void)demoTransitionUIViewAnimation
{
self.animationView.frame = CGRectMake(50.0, 250.0, 200.0, 200.0);
[UIView beginAnimations:@"Animation" context:nil];
[UIView setAnimationDuration:3.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationWillStartSelector:@selector(startAnimation)];
[UIView setAnimationDidStopSelector:@selector(stopAnimation)];
[UIView setAnimationRepeatCount:5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.animationView cache:YES];
self.animationView.backgroundColor = [UIColor blueColor];
[UIView commitAnimations];
}
轉(zhuǎn)場動畫有個參數(shù)cache,可以設(shè)置為YES或者NO,它們有什么區(qū)別呢?
首先把要動畫的視圖進(jìn)行截圖(此處為何要截圖說明一下,因為要動畫的視圖上邊一般都會有好多的控件,如果讓動畫直接操作視圖,那么視圖帶著自身內(nèi)部的控件,這樣做動畫的話會增加系統(tǒng)的負(fù)擔(dān),從而使動畫效率降低,所以為了減輕系統(tǒng)負(fù)擔(dān),使動畫更流暢,才對動畫視圖進(jìn)行截圖處理已完成動畫效果),然后對視圖的截圖進(jìn)行動畫操作。
當(dāng)
cache選為YES時:系統(tǒng)只會在動畫開始的時候?qū)σ晥D進(jìn)行截圖,然后一直到動畫結(jié)束,都用開始截的那張圖,這種方法好處是減輕系統(tǒng)負(fù)擔(dān),使動畫效果更流暢、更自然。但這樣也必會有缺點:就是當(dāng)動畫視圖中的控件有變化的時候,不能立即更新在視圖上,從而達(dá)不到實時更新的效果。當(dāng)
cache選為NO時:系統(tǒng)會在動畫整個過程中對視圖進(jìn)行實時截圖,這樣當(dāng)視圖中的控件更新時也會實時顯示在動畫過程中,彌補了cache選擇yes得缺點,但這也把cache選擇yes的優(yōu)點變成缺點,是系統(tǒng)效率變慢,如果動畫視圖中的控件過多,會讓動畫看起來不那么自然。
這里還要注意:如果要在轉(zhuǎn)換期間更改視圖的外觀 - 例如,從一個視圖翻轉(zhuǎn)到另一個視圖 - 然后使用容器視圖(UIView的實例),如下所示:
Begin an animation block.Set the transition on the container view.Remove the subview from the container view.Add the new subview to the container view.Commit the animation block.
iOS 4.0及更高版本不鼓勵使用此方法。 您應(yīng)該使用transition(with:duration:options:animations:completion:)
方法來執(zhí)行轉(zhuǎn)換。
后記
未完,待續(xù)~~~
