pop架构
由四大部分组成
1.Animations
2.Engine
3.Utility
4.WebCore
第一部分Animations
这一部分当中定义了动画的类型,一共4种,分别是:
POPBasicAnimation //基本动画固定时间间隔
POPCustomAnimation //自定义动画
POPDecayAnimation //带阻尼动画效果
POPSpringAnimation //弹簧动画效果
各自有不同的使用场景
再看一下此目录中的类继承的结构关系
POPAnimation
———> POPPropertyAnimation
———>POPBasicAnimation
———>POPDecayAnimation
———>POPSpringAnimation
———>POPCustomAnimation
POPAnimation中定义了各种动画中需要的公有属性
name beginTime tracer block 以及相应的代理回调,类扩展等等,以及引用了POPAnimationInternal中的私有结构体等(_POPAnimationState)
basic动画示例
spring动画
想了下,写这些东西网上随便都能查的到啊,这样还是看看源码pop如何具体实现一个动画效果的,所以请抛开上面所说的Animations框架主题
先从一个最基本的basic动画的创建开始
1. POPBasicAnimation *anBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionX];
2. anBasic.toValue = @(testView.center.y+50);
3. anBasic.beginTime = CACurrentMediaTime()+2.0f;
4. [testView pop_addAnimation:anBasic forKey:@"position"];
先看一下代码的执行流程
POPBasicAnimation *anBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionX];
然后进入到这个方法
1.
+ (instancetype)animationWithPropertyNamed:(NSString*)aName
{
POPBasicAnimation*anim = [selfanimation];
anim.property= [POPAnimatable PropertypropertyWithName:aName];//跳入2中
return anim;
}
(POPBasicAnimation)
2.
+ (id)propertyWithName:(NSString*)aName
{
return[self propertyWithName:aNameinitializer:NULL];//跳入3中
}
(POPAnimatableProperty)
3.
/**
* 返回要进行的动画属性
*
* @param aName 属性名称
* @param aBlock
*
* @return <#return value description#>
*/
+ (id)propertyWithName:(NSString*)aName initializer:(void(^)(POPMutableAnimatableProperty*prop))aBlock
{
POPAnimatableProperty*prop =nil;//声明一个空的POPAnimatableProperty对象
staticNSMutableDictionary*_propertyDict =nil;
if(nil== _propertyDict) {
_propertyDict = [[NSMutableDictionary alloc]initWithCapacity:10];//实例化一个静态可变字典
}
prop = _propertyDict[aName];
if(nil!= prop) {
returnprop;//如果prop不等于nil则返回prop
}
NSUIntegerstaticIdx =staticIndexWithName(aName);//如果prop为nil,则通过此函数定位下标
if(NSNotFound!= staticIdx) {
//如果下标不为NSNotFound,则新建一个POPStaticAnimatableProperty对象
POPStaticAnimatableProperty*staticProp = [[POPStaticAnimatableProperty alloc]init];
//让新建对象的结构体指向通过下标根据结构体数组找到的结构体(语言组织有点问题)
staticProp->_state= &_staticStates[staticIdx];
//添加字典中的key-value,key是aName,Value是POPStaticAnimatableProperty对象
_propertyDict[aName] = staticProp;
prop = staticProp;
}else if(NULL!= aBlock) {
//如果block参数不为空,则创建POPMutableAnimatableProperty对象
POPMutableAnimatableProperty*mutableProp =[[POPMutableAnimatableProperty alloc]init];
mutableProp.name= aName;
mutableProp.threshold=1.0;
aBlock(mutableProp);执行block
prop = [mutableProp copy];
}
return prop;
}
接着
anBasic.toValue = @(testView.center.y+50);
执行
- (void)setToValue:(id)aValue
{
POPPropertyAnimationState*s =__state;
VectorRefvec =POPUnbox(aValue, s->valueType, s->valueCount,YES);//解包一个向量,把point,size ,rect,color对象转换为vector
//vector的各种逻辑判断
if(!vec_equal(vec, s->toVec)) {
s->toVec= vec;
// invalidate to dependent state
s->didReachToValue=false;
s->distanceVec=NULL;
if(s->tracing) {
//把动画过程中的属性变化加入追踪器,生成event加入events数组中
[s->tracerupdateToValue:aValue];
}
// automatically unpause active animations
if(s->active&& s->paused) {
s->setPaused(false);
}
}
}
最后看一下
[testViewpop_addAnimation:anBasicforKey:@"position"];
是如何把一个animation加到view上一个动画就能够动起来
先看一下都调用了哪些方法
- (void)pop_addAnimation:(POPAnimation*)anim forKey:(NSString*)key
{
[[POPAnimator sharedAnimator]addAnimation:anim forObject:self key:key];
}
继续...
+ (id)sharedAnimator
{
staticPOPAnimator* _animator =nil;
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
_animator = [[POPAnimator alloc] init];
});
return_animator;
}
继续
- (id)init
{
self= [super init];
if(nil==self)return nil;
#if TARGET_OS_IPHONE
_displayLink= [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];
//这个时候为pause状态为yes动画还没开始跑
_displayLink.paused=YES;
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop]forMode:NSRunLoopCommonModes];
#else
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
CVDisplayLinkSetOutputCallback(_displayLink, displayLinkCallback, (__bridgevoid*)self);
#endif
_dict=POPDictionaryCreateMutableWeakPointerToStrongObject(5);
_lock=OS_SPINLOCK_INIT;
returnself;
}
看见没在这里创建了一个CADisplayLink对象(关于CADisplayLink是个什么东西,可以自行google)
重点来了,这里把_displayLink对象加入到主线程,然后调用render方法
再看一下之后调用的
- (void)addAnimation:(POPAnimation*)anim forObject:(id)obj key:(NSString*)key
{
//判断为空则返回
if(!anim || !obj) {
return;
}
// support arbitrarily many nil keys
if(!key) {
key = [[NSUUID UUID]UUIDString];
}
// lock
OSSpinLockLock(&_lock);
// get key, animation dict associated with object
// 把之前init方法中创建的_dict赋给keyAnimationDict
NSMutableDictionary*keyAnimationDict = (__bridgeid)CFDictionaryGetValue(_dict, (__bridgevoid*)obj);
// update associated animation state
if(nil== keyAnimationDict) {
//判断为空的情况下的处理
keyAnimationDict = [NSMutableDictionary dictionary];
CFDictionarySetValue(_dict, (__bridgevoid*)obj, (__bridgevoid*)keyAnimationDict);
}else{
// if the animation instance already exists, avoid cancelling only to restart
POPAnimation*existingAnim = keyAnimationDict[key];//根据所传入的key查找animation
if(existingAnim) {
// unlock
OSSpinLockUnlock(&_lock);
if(existingAnim == anim) {
//如果此查找到的existingAnim等于传入的anim则返回
return;
}
这里是应该防止,多个不同的animation公用一个key值
[selfremoveAnimationForObject:objkey:keycleanupDict:NO];
// lock
OSSpinLockLock(&_lock);
}
}
keyAnimationDict[key] = anim;
// create entry after potential removal
POPAnimatorItemRefitem(new POPAnimatorItem(obj, key, anim));
// add to list and pending list
_list.push_back(item);
_pendingList.push_back(item);
// support animation re-use, reset all animation state
POPAnimationGetState(anim)->reset(true);
// update display link
这个时候呢 根据方法实现给_displayLink.paused= NO;了 开始跑了
updateDisplayLink(self);
// unlock
OSSpinLockUnlock(&_lock);
// schedule runloop processing of pending animations
[self_scheduleProcess PendingList];
}
最后进入- (void)_scheduleProcessPendingList
- (void)_scheduleProcessPendingList
{
// see WebKit for magic numbers, eghttp://trac.webkit.org/changeset/166540
static const CFIndexCATransactionCommitRunLoopOrder =2000000;
static const CFIndexPOPAnimationApplyRunLoopOrder = CATransactionCommitRunLoopOrder -1;
// lock
OSSpinLockLock(&_lock);
if(!_pendingListObserver) {
__weakPOPAnimator*weakSelf =self;
//监听runloop
_pendingListObserver=CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault,kCFRunLoopBeforeWaiting|kCFRunLoopExit,false, POPAnimationApplyRunLoopOrder, ^(CFRunLoopObserverRefobserver,CFRunLoopActivityactivity) {
[weakSelf _processPendingList];//kCFRunLoopBeforeWaiting|kCFRunLoopExit下回调清除动画
});
if(_pendingListObserver) {
添加到主线程的runloop中
CFRunLoopAddObserver(CFRunLoopGetMain(),_pendingListObserver,kCFRunLoopCommonModes);
}
}
// unlock
OSSpinLockUnlock(&_lock);
}
然后呢_displaylink就开始调用rend方法进行动画了,就开始以1秒60次的频率刷新UI
整个过程就是这么一个过程