OC版 https://github.com/IFTTT/JazzHands
switf版 https://github.com/IFTTT/RazzleDazzle
簡介
Jazz Hand是一個簡單的基于keyframe的UIKit動畫框架。動畫可以通過手勢,scrollviews,Kvo或者ReactiveCocoa控制。常見用途:制作一個拖動動畫的引導(dǎo)頁.以下是我寫的一個Demo.

安裝
OC版:
pod "JazzHands"
swift版:
pod "RazzleDazzle"
類圖

IFTTTAnimatior
導(dǎo)演類,里面有一個動畫(IFTTTAnimation
)數(shù)組管理所有動畫的添加/刪除/執(zhí)行.IFTTTAnimatable
執(zhí)行動畫類.
重要: 定義了核心協(xié)議(接口),animate:(CGFloat)time;
計算每一個時間點當(dāng)前對象的值.每一種動畫都要實現(xiàn)這個接口.如IFTTTAlphaAnimation
類,計算一個時間點對應(yīng)的對象的alpha值-
IFTTTAnimation
動畫基類,定義了一個對象的動畫.僅僅只是對類中的IFTTTFilemstrip
進行一個簡單的封裝.注: 每種動畫都繼承IFTTTAnimation和實現(xiàn)<IFTTTAnimatable>協(xié)議才會正常工作.
IFTTTFilmstrip
膠片類,有一個關(guān)鍵幀(IFTTTKeyframe)數(shù)組.,添加/修改/獲取對應(yīng)關(guān)鍵幀(IFTTTKeyframe)的值.通過valueAtTime:可以計算兩個相鄰關(guān)鍵幀之間的的值.這個值在執(zhí)行動畫時- animate
使用.IFTTTKeyframe
關(guān)鍵幀類,描述每一個關(guān)鍵幀的時間對應(yīng)的值.
分析:
jazzhand主要應(yīng)用在scrollviews
,同時封裝了IFTTTAnimatedPagingScrollViewController
方便我們繼承使用.目前這個類scrollview
只支持橫向滾動,并不支持縱向滾動.jazzhand框架是基于關(guān)鍵幀的動畫,這個概念其實跟Core Animation
的概念是一樣的. 只不過跟core Animation有不同一點的是,jazzhand框架的動畫驅(qū)動是坐標(biāo)驅(qū)動.
舉個例子,在Core Animation
中,我們只需要設(shè)置軌跡,方向,時間就可以提交了.接下就由Core Animation
負責(zé)計算,就可以看到App能執(zhí)行一段動畫.這里設(shè)置了時間5s.在APP接下來的5s中,Core Animation
每1/30秒重新計算一次imageview
的位置并調(diào)用[self ifNeedLayout]
方法進行更行.然后就形成了我們所看到的動畫.
[UIView beginAnimations:@"jk" context:nil];
// 設(shè)置動畫的方向
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:imageView cache:YES];
// 設(shè)置動畫持續(xù)時間
[UIView setAnimationDuration:5];
// 設(shè)置動畫效果過渡的狀態(tài)
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
// 提交動畫
[UIView commitAnimations];
}
但是Jazzhand中,卻以scrollview.contentOffset
作為動畫執(zhí)行的time,在[scrollview didScroll]
代理中重新計算視圖的位置.

在Jazzhand中有一個重要的方法
- (void)keepView:(UIView *)view
onPages:(NSArray *)pages
atTimes:(NSArray *)times
withOffsets:(NSArray *)offsets
withAttribute:(IFTTTHorizontalPositionAttribute)attribute
pages和offsets的個數(shù)要相同.不然會產(chǎn)生致命錯誤(crash)
其中每個page和time對應(yīng)的是:
view.frame.size.x = page * pageWidth
scrollview.contentOffset = time * pageWidth
當(dāng)time = 1時, 即scrollview滾到第二頁的時候,scrollview.contentOffset=(pageWidth * 1).然后我們必須設(shè)置時間time所對應(yīng)的view的位置.可以想象每拖動一個頁面,相當(dāng)于view對象進行時間0到1的動畫.
每一個動畫(animation)都擁有一個膠卷(filmstrip),每一個膠卷都包含該了該動作的所有關(guān)鍵幀(keyframe).隨著屏幕拖拽,JazzHands會根據(jù)約束和時間(contentOffset)計算對象的位置.只要刷新的頻率只夠高.我們?nèi)搜劬涂床怀鍪侵匦庐嬌先?而是連續(xù)的動畫了.
使用:
- @interface IntrotductionController:IFTTTAnimatedPagingScrollViewController
IFTTTAnimatedPagingScrollViewController
繼承viewcontroller
,有子成員scrollview
,封裝了contentview
.所以只需要將對象加入到contentview
中就可以.
- 重載
numberOfPage
方法系統(tǒng)默認是2 - 如果不需要,就不要給對象添加約束.
不要給x值添加約束. 原因見4.
-
[self keepView:self.circle onPages:@[@(0), @(1)]];
設(shè)置對象的x值的關(guān)鍵幀. 這句代碼的意思是,當(dāng)視圖view移動到scrollview
的contentOffset
為0時circle
的位置也為0, 當(dāng)拖動到contentOffset
為1時,circle
的位置也是1,這句代碼內(nèi)部幫對象添加了x值的約束.如果你之前為x值添加其他約束,這里在運行時候回出現(xiàn)約束沖突錯誤.同時我們只能選擇對象在屏幕中左中右三個相對位置.
注: 使對象相對于屏幕位置不動的方法
// 設(shè)置time即contentOffset不變,即使相對屏幕不變.
// 在index-1滑動到index時,leimuImgHeart的位置從index-1.15滑動到index-0.15.兩者滑動的距離相等,速度相等.
// 所以視覺上是相對于屏幕位置不變.同時,第4中不設(shè)置times參數(shù)也是默認相對于屏幕位置不變
[self keepView:leimuImgHeart onPages:@[@(index-1.15),@(index-0.15), @(index-1.15)] atTimes:@[@(index-1),@(index),@(index+1)] withAttribute:IFTTTHorizontalPositionAttributeCenterX offset:0];
Time變化引起offset變化,leimuImgHeart也得同步跟time一起變化
-
定義你自己的動畫
// 最好使用autolayout固定視圖的位置 NSLayoutConstraint * topConstraint = [NSLayoutConstraint constraintWithItem:leimuImgHeart attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.f]; [self.contentView addConstraint:topConstraint]; // 添加一個約束幀動畫,即約束隨time的變化而變化 IFTTTConstraintMultiplierAnimation *constantAnimation = [IFTTTConstraintMultiplierAnimation animationWithSuperview:self.contentView constraint:topConstraint attribute:IFTTTLayoutAttributeHeight referenceView:self.contentView]; [constantAnimation addKeyframeForTime:index-1 multiplier:-0.2f]; [constantAnimation addKeyframeForTime:index multiplier:0.3f]; [self.animator addAnimation:constantAnimation];