一、前言
本文主要专注于源码分析,具体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对象之间的相互转化。