一、前言
本文主要專注於原始碼分析,具體pop的相關使用,可參考下文連結
二、POP原始碼架構
pop原始碼主要分為Animations、Engine、Uility和WebCore四部分,每一部分承擔不同的職責。
- Animations:包含了pop中所有的動畫型別
- Engine:負責pop中的動畫處理
- Uitity:常用到的一些工具類
- WebCore:包括矩陣處理以及貝塞爾曲線等
三、POP動畫型別
pop中可使用的動畫包括POPBasicAnimation、POPSpringAnimation、POPDecayAnimation和POPCustomAnimation四種,具體類之間的關係如下:
1.POPAnimation
該類類似於CAAnimation,是動畫的抽象基類,提供一些共用的屬性和方法。
@interface POPAnimation : NSObject
//屬性對應的名稱,用於區分動畫物件
@property (copy, nonatomic) NSString *name;
//開啟動畫的時間
@property (assign, nonatomic) CFTimeInterval beginTime;
@property (weak, nonatomic) id delegate;
//用於記錄動畫過程
@property (readonly, nonatomic) POPAnimationTracer *tracer;
//動畫開始時被呼叫
@property (copy, nonatomic) void (^animationDidStartBlock)(POPAnimation *anim);
//當動畫屬性值達到或超過設定的值時被呼叫
@property (copy, nonatomic) void (^animationDidReachToValueBlock)(POPAnimation *anim);
//動畫結束時被呼叫
@property (copy, nonatomic) void (^completionBlock)(POPAnimation *anim, BOOL finished);
//動畫每執行完一幀後被呼叫
@property (copy, nonatomic) void (^animationDidApplyBlock)(POPAnimation *anim);
//動畫執行完後,是否移除動畫,預設為NO,若設定為YES,動畫執行完後,會恢復原狀
@property (assign, nonatomic) BOOL removedOnCompletion;
//獲取動畫執行的狀態
@property (assign, nonatomic, getter = isPaused) BOOL paused;
//是否執行來回動畫
@property (assign, nonatomic) BOOL autoreverses;
//動畫重複次數
@property (assign, nonatomic) NSInteger repeatCount;
//是否一直重複動畫
@property (assign, nonatomic) BOOL repeatForever;
@end
//獲取動畫的執行狀態
@protocol POPAnimationDelegate <NSObject>
@optional
- (void)pop_animationDidStart:(POPAnimation *)anim;
- (void)pop_animationDidReachToValue:(POPAnimation *)anim;
- (void)pop_animationDidStop:(POPAnimation *)anim finished:(BOOL)finished;
- (void)pop_animationDidApply:(POPAnimation *)anim;
@end
複製程式碼
a. POPAnimation為抽象類,不能被例項化
- (id)init
{
[NSException raise:NSStringFromClass([self class]) format:@"Attempting to instantiate an abstract class. Use a concrete subclass instead."];
return nil;
}
複製程式碼
b. POPAnimation的初始化:在初始化方法中,建立了一個POPAnimationState物件,並將自己作為引數傳遞過去。
- (void)_initState
{
_state = new POPAnimationState(self);
}
複製程式碼
POPAnimationState為一個struct宣告,裡面包含與POPAnimation對應的屬性
struct _POPAnimationState
{
id __unsafe_unretained self;
POPAnimationType type;
NSString *name;
NSUInteger ID;
CFTimeInterval beginTime;
CFTimeInterval startTime;
CFTimeInterval lastTime;
id __weak delegate;
POPAnimationDidStartBlock animationDidStartBlock;
POPAnimationDidReachToValueBlock animationDidReachToValueBlock;
POPAnimationCompletionBlock completionBlock;
POPAnimationDidApplyBlock animationDidApplyBlock;
NSMutableDictionary *dict;
POPAnimationTracer *tracer;
CGFloat progress;
NSInteger repeatCount;
...
}
複製程式碼
c. POPAnimation的setter和getter方法
- (BOOL)isPaused
{
return _state->paused;
}
- (void)setPaused:(BOOL)paused
{
_state->setPaused(paused ? true : false);
}
- (NSInteger)repeatCount
{
if (_state->autoreverses) {
return _state->repeatCount / 2;
} else {
return _state->repeatCount;
}
}
- (void)setRepeatCount:(NSInteger)repeatCount
{
if (repeatCount > 0) {
if (repeatCount > NSIntegerMax / 2) {
repeatCount = NSIntegerMax / 2;
}
if (_state->autoreverses) {
_state->repeatCount = (repeatCount * 2);
} else {
_state->repeatCount = repeatCount;
}
}
}
複製程式碼
我們可以看到setter其實就是將對應的屬性賦值給_state,getter也是從_state中獲取再返回。也就是說其實POPAnimation可以看作是一箇中介者,是OC暴露的介面,實際上操作這些屬性還是通過POPAnimationState結構體。
d.使用巨集來簡化OC物件與結構體之間屬性的轉換
#define FB_PROPERTY_GET(stype, property, ctype) \
- (ctype)property { \
return ((stype *)_state)->property; \
}
#define FB_PROPERTY_SET(stype, property, mutator, ctype, ...) \
- (void)mutator (ctype)value { \
if (value == ((stype *)_state)->property) \
return; \
((stype *)_state)->property = value; \
__VA_ARGS__ \
}
#define DEFINE_RW_PROPERTY_OBJ(stype, flag, mutator, ctype, ...) \
FB_PROPERTY_GET (stype, flag, ctype) \
FB_PROPERTY_SET (stype, flag, mutator, ctype, __VA_ARGS__)
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidStartBlock, setAnimationDidStartBlock:, POPAnimationDidStartBlock);
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidReachToValueBlock, setAnimationDidReachToValueBlock:, POPAnimationDidReachToValueBlock);
複製程式碼
對於需要特殊處理的setter和getter方法,則需要重寫,而常規的setter和getter方法,則通過巨集來簡化這一過程。
e.重寫valueForUndefinedKey方法
- (id)valueForUndefinedKey:(NSString *)key
{
return _state->dict[key];
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
if (!value) {
[_state->dict removeObjectForKey:key];
} else {
if (!_state->dict)
_state->dict = [[NSMutableDictionary alloc] init];
_state->dict[key] = value;
}
}
複製程式碼
在KVC呼叫valueForKey方法時,若key不存在,則會丟擲NSUndefinedkeyException異常,為了避免該異常,重寫了valueForUndefinedKey方法。
2.POPAnimation分類
該分類主要提供了外部對動畫增刪查的介面,但實際上真正執行這些操作的是POPAnimator物件。
@interface NSObject (POP)
- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key;
- (void)pop_removeAllAnimations;
- (void)pop_removeAnimationForKey:(NSString *)key;
- (NSArray *)pop_animationKeys;
- (id)pop_animationForKey:(NSString *)key;
@end
@implementation NSObject (POP)
- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key
{
[[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key];
}
- (void)pop_removeAllAnimations
{
[[POPAnimator sharedAnimator] removeAllAnimationsForObject:self];
}
- (void)pop_removeAnimationForKey:(NSString *)key
{
[[POPAnimator sharedAnimator] removeAnimationForObject:self key:key];
}
- (NSArray *)pop_animationKeys
{
return [[POPAnimator sharedAnimator] animationKeysForObject:self];
}
- (id)pop_animationForKey:(NSString *)key
{
return [[POPAnimator sharedAnimator] animationForObject:self key:key];
}
@end
複製程式碼
四、總結
本小節主要介紹了pop的大致架構以及動畫的基類POPAnimation的相關內容。該小節比較值得關注的一點就是pop將OC物件和struct物件之間的相互轉化。