pop動(dòng)畫(huà)框架源碼初步探究

pop架構(gòu)

由四大部分組成

1.Animations

2.Engine

3.Utility

4.WebCore

第一部分Animations

這一部分當(dāng)中定義了動(dòng)畫(huà)的類(lèi)型械拍,一共4種,分別是:

POPBasicAnimation ?? ? ? //基本動(dòng)畫(huà)固定時(shí)間間隔

POPCustomAnimation ? ?//自定義動(dòng)畫(huà)

POPDecayAnimation ? ? ?//帶阻尼動(dòng)畫(huà)效果

POPSpringAnimation ? ? //彈簧動(dòng)畫(huà)效果

各自有不同的使用場(chǎng)景

再看一下此目錄中的類(lèi)繼承的結(jié)構(gòu)關(guān)系

POPAnimation

———> POPPropertyAnimation

———>POPBasicAnimation

———>POPDecayAnimation

———>POPSpringAnimation

———>POPCustomAnimation

POPAnimation中定義了各種動(dòng)畫(huà)中需要的公有屬性

name beginTime tracer block 以及相應(yīng)的代理回調(diào),類(lèi)擴(kuò)展等等乾戏,以及引用了POPAnimationInternal中的私有結(jié)構(gòu)體等(_POPAnimationState)

basic動(dòng)畫(huà)示例

spring動(dòng)畫(huà)

想了下善玫,寫(xiě)這些東西網(wǎng)上隨便都能查的到啊洒敏,這樣還是看看源碼pop如何具體實(shí)現(xiàn)一個(gè)動(dòng)畫(huà)效果的,所以請(qǐng)拋開(kāi)上面所說(shuō)的Animations框架主題

先從一個(gè)最基本的basic動(dòng)畫(huà)的創(chuàng)建開(kāi)始

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"];

先看一下代碼的執(zhí)行流程

POPBasicAnimation *anBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionX];

然后進(jìn)入到這個(gè)方法

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.

/**

* 返回要進(jìn)行的動(dòng)畫(huà)屬性

*

*? @param aName ?屬性名稱(chēng)

*? @param aBlock

*

*? @return <#return value description#>

*/

+ (id)propertyWithName:(NSString*)aName initializer:(void(^)(POPMutableAnimatableProperty*prop))aBlock

{

POPAnimatableProperty*prop =nil;//聲明一個(gè)空的POPAnimatableProperty對(duì)象

staticNSMutableDictionary*_propertyDict =nil;

if(nil== _propertyDict) {

_propertyDict = [[NSMutableDictionary alloc]initWithCapacity:10];//實(shí)例化一個(gè)靜態(tài)可變字典

}

prop = _propertyDict[aName];

if(nil!= prop) {

returnprop;//如果prop不等于nil則返回prop

}

NSUIntegerstaticIdx =staticIndexWithName(aName);//如果prop為nil拿愧,則通過(guò)此函數(shù)定位下標(biāo)

if(NSNotFound!= staticIdx) {

//如果下標(biāo)不為NSNotFound,則新建一個(gè)POPStaticAnimatableProperty對(duì)象

POPStaticAnimatableProperty*staticProp = [[POPStaticAnimatableProperty alloc]init];

//讓新建對(duì)象的結(jié)構(gòu)體指向通過(guò)下標(biāo)根據(jù)結(jié)構(gòu)體數(shù)組找到的結(jié)構(gòu)體(語(yǔ)言組織有點(diǎn)問(wèn)題)

staticProp->_state= &_staticStates[staticIdx];

//添加字典中的key-value,key是aName碌尔,Value是POPStaticAnimatableProperty對(duì)象

_propertyDict[aName] = staticProp;

prop = staticProp;

}else if(NULL!= aBlock) {

//如果block參數(shù)不為空,則創(chuàng)建POPMutableAnimatableProperty對(duì)象

POPMutableAnimatableProperty*mutableProp =[[POPMutableAnimatableProperty alloc]init];

mutableProp.name= aName;

mutableProp.threshold=1.0;

aBlock(mutableProp);執(zhí)行block

prop = [mutableProp copy];

}

return prop;

}

接著

anBasic.toValue = @(testView.center.y+50);

執(zhí)行

- (void)setToValue:(id)aValue

{

POPPropertyAnimationState*s =__state;

VectorRefvec =POPUnbox(aValue, s->valueType, s->valueCount,YES);//解包一個(gè)向量浇辜,把point券敌,size ,rect柳洋,color對(duì)象轉(zhuǎn)換為vector

//vector的各種邏輯判斷

if(!vec_equal(vec, s->toVec)) {

s->toVec= vec;

// invalidate to dependent state

s->didReachToValue=false;

s->distanceVec=NULL;

if(s->tracing) {

//把動(dòng)畫(huà)過(guò)程中的屬性變化加入追蹤器待诅,生成event加入events數(shù)組中

[s->tracerupdateToValue:aValue];

}

// automatically unpause active animations

if(s->active&& s->paused) {

s->setPaused(false);

}

}

}

最后看一下

[testViewpop_addAnimation:anBasicforKey:@"position"];

是如何把一個(gè)animation加到view上一個(gè)動(dòng)畫(huà)就能夠動(dòng)起來(lái)

先看一下都調(diào)用了哪些方法

- (void)pop_addAnimation:(POPAnimation*)anim forKey:(NSString*)key

{

[[POPAnimator sharedAnimator]addAnimation:anim forObject:self key:key];

}

繼續(xù)...

+ (id)sharedAnimator

{

staticPOPAnimator* _animator =nil;

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

_animator = [[POPAnimator alloc] init];

});

return_animator;

}

繼續(xù)

- (id)init

{

self= [super init];

if(nil==self)return nil;

#if TARGET_OS_IPHONE

_displayLink= [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];

//這個(gè)時(shí)候?yàn)閜ause狀態(tài)為yes動(dòng)畫(huà)還沒(méi)開(kāi)始跑

_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;

}

看見(jiàn)沒(méi)在這里創(chuàng)建了一個(gè)CADisplayLink對(duì)象(關(guān)于CADisplayLink是個(gè)什么東西,可以自行g(shù)oogle)

重點(diǎn)來(lái)了,這里把_displayLink對(duì)象加入到主線程熊镣,然后調(diào)用render方法

再看一下之后調(diào)用的

- (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方法中創(chuàng)建的_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];//根據(jù)所傳入的key查找animation

if(existingAnim) {

// unlock

OSSpinLockUnlock(&_lock);

if(existingAnim == anim) {

//如果此查找到的existingAnim等于傳入的anim則返回

return;

}

這里是應(yīng)該防止卑雁,多個(gè)不同的animation公用一個(gè)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

這個(gè)時(shí)候呢 根據(jù)方法實(shí)現(xiàn)給_displayLink.paused= NO;了 開(kāi)始跑了

updateDisplayLink(self);

// unlock

OSSpinLockUnlock(&_lock);

// schedule runloop processing of pending animations

[self_scheduleProcess PendingList];

}

最后進(jìn)入- (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;

//監(jiān)聽(tīng)runloop

_pendingListObserver=CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault,kCFRunLoopBeforeWaiting|kCFRunLoopExit,false, POPAnimationApplyRunLoopOrder, ^(CFRunLoopObserverRefobserver,CFRunLoopActivityactivity) {

[weakSelf _processPendingList];//kCFRunLoopBeforeWaiting|kCFRunLoopExit下回調(diào)清除動(dòng)畫(huà)

});

if(_pendingListObserver) {

添加到主線程的runloop中

CFRunLoopAddObserver(CFRunLoopGetMain(),_pendingListObserver,kCFRunLoopCommonModes);

}

}

// unlock

OSSpinLockUnlock(&_lock);

}

然后呢_displaylink就開(kāi)始調(diào)用rend方法進(jìn)行動(dòng)畫(huà)了,就開(kāi)始以1秒60次的頻率刷新UI

整個(gè)過(guò)程就是這么一個(gè)過(guò)程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绪囱,一起剝皮案震驚了整個(gè)濱河市测蹲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鬼吵,老刑警劉巖弛房,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異而柑,居然都是意外死亡文捶,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)媒咳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)粹排,“玉大人,你說(shuō)我怎么就攤上這事涩澡⊥缍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵妙同,是天一觀的道長(zhǎng)射富。 經(jīng)常有香客問(wèn)我,道長(zhǎng)粥帚,這世上最難降的妖魔是什么胰耗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮芒涡,結(jié)果婚禮上柴灯,老公的妹妹穿的比我還像新娘。我一直安慰自己费尽,他們只是感情好赠群,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著旱幼,像睡著了一般查描。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天冬三,我揣著相機(jī)與錄音鸯两,去河邊找鬼。 笑死长豁,一個(gè)胖子當(dāng)著我的面吹牛钧唐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匠襟,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼钝侠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了酸舍?” 一聲冷哼從身側(cè)響起帅韧,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啃勉,沒(méi)想到半個(gè)月后忽舟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡淮阐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年叮阅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泣特。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浩姥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出状您,到底是詐尸還是另有隱情勒叠,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布膏孟,位于F島的核電站眯分,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏柒桑。R本人自食惡果不足惜弊决,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望幕垦。 院中可真熱鬧丢氢,春花似錦、人聲如沸先改。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)仇奶。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間该溯,已是汗流浹背岛抄。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狈茉,地道東北人夫椭。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像氯庆,于是被迫代替她去往敵國(guó)和親蹭秋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容