iOS動効-利用POP動畫實現卡片切換動畫
Pop is an extensible animation engine for iOS and OS X. In addition to basic static animations, it supports spring and decay dynamic animations, making it useful for building realistic, physics-based interactions. The API allows quick integration with existing Objective-C codebases and enables the animation of any property on any object. It's a mature and well-tested framework that drives all the animations and transitions in Paper.
以上是pop動畫在github上的官方解釋,大體上的意思是pop是一個extensible(可擴展)的動畫引擎,提供基礎的Basic 靜態動畫以及支持彈簧和衰減動畫,用來構建高可用性的真實、物理特性的交互體驗,使用oc作為基礎,可用戶擴展到任何的oc的Object的屬性,是一個非常易于測試的框架,并且在非死book自家的Paper上應用。
pop首先是一個動畫引擎,那本質上不再是基于apple的CoreAnimation框架的,是自己實現的一套跟CoreAnimation一樣的動畫引擎框架,內部使用了CADisplayer的每秒60幀高素質的渲染技術,充分使用了GPU的能力,性能表現很樂觀,而能用作任何基于NSObject上,又增加了擴展性,比如說UIView背景顏色的動態切換,比如說聲音的漸隱漸顯等等,這是對CA不足的充分補充,而引出的physics特性,更引發了apple后來推出了UIDynamic(UIKit動力學)來彌補iOS平臺上的物理特性動畫的不足,也大大簡化了動畫的開發難度。POP 使用 Objective-C++ 編寫,Objective-C++ 是對 C++ 的擴展,就像 Objective-C 是 C 的擴展。而至于為什么他們用 Objective-C++ 而不是純粹的 Objective-C,原因是他們更喜歡 Objective-C++ 的語法特性所提供的便利。那我們弄清楚了pop的本質,就開始介紹一下這個框架。
基本的pop動畫的使用我就不再贅述,很多文章都有介紹,我在剛接觸的pop的時候有很多疑問,主要是在實際運用的時候出現的代碼實踐的問題,因為之前一直是用CA的,總會用CA的用法來尋找pop的使用技巧,那么就有以下幾個問題要搞清楚:
1.具有多個動畫的聯合動畫如何實現,CA中有CAAnimationGroup的概念,能實現動畫組,pop中該怎么辦?
2.有沒有重復播放動畫的概念,因為有些動畫是必須重復播放的。
3.在現在大量使用autolayout的布局的時候,如何使用pop動畫
結合以上的問題,我自己做了一個卡片切換動畫的Demo來說明一下。
卡片切換的交互動畫
卡片設計比較粗糙,沒有設置卡片上明確的細小的分欄和文字切換,只是簡單的模仿了卡片切換和卡片上圓環的切換。
動畫組的概念,這個問題在做的時候不糾結了,因為pop提供pop_addAnimation這樣的API,實際上要想實現動畫組概念,在實踐中就將生產Animation的代碼單獨封裝成函數,然后多次調用pop_addAnimation就好了。比方說,我就會這么干
-(void)setCenter:(CGPoint)center Duration:(CGFloat)duration Card:(cardView *)card Index:(NSUInteger)index{
POPBasicAnimation * bAni = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
bAni.toValue = [NSValue valueWithCGPoint:center];
bAni.duration = duration;
[bAni setCompletionBlock:^(POPAnimation *ani, BOOL is) {
if (is) {
card.hidden = NO;
}
}];
[card pop_addAnimation:bAni forKey:@"center"];
}
-(void)setScaleWithScalePercent:(CGFloat) percent Duration:(CGFloat)duration Card:(cardView *)card{
POPBasicAnimation * bAni = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
bAni.toValue = [NSValue valueWithCGSize:CGSizeMake(percent, percent)];
bAni.duration = duration;
[card.layer pop_addAnimation:bAni forKey:@"123"];
}
-(void)setRorationWithAngle:(CGFloat)angele Duration:(CGFloat)duration Card:(cardView *)card{
POPBasicAnimation * bAni = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerRotation];
bAni.duration = duration;
bAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
bAni.toValue = [NSNumber numberWithFloat:angele];
[card.layer pop_addAnimation:bAni forKey:@"213"];
}
將上述對cardView增加動畫的方法寫好,然后多次調用
[self setScaleWithScalePercent:scalePercent Duration:0.0001f Card:card];
[self setRorationWithAngle:rotation Duration:0.001f Card:card];
對于重復的動畫使用,可以利用如下:
-(void)performAnimation
{
[self setAnimationWithBounciness:self.bouncinessSlider.value andSpeed:self.speedSlider.value];
}
定義好執行方法,在completionBlock中重復調用執行動畫的方法就Ok,當然,你也可以對pop動畫對象再封裝,實現重復次數。
anim.completionBlock = ^(POPAnimation *anim, BOOL finished)
{
if (finished) {
[self performAnimation];
}
};
對于autolayout的動畫
有人寫過這樣的例子,以下是代碼,pop是支持更新layout的約束的,這對更新具體某個約束是比較有效的,而如果你在做某個類似翻轉動畫的時候,必定要用到layer層動畫,那單單靠更新約束就不太能滿足要求,但是恰好你在使用Pop的layer層動畫的時候,該layer屬于的View上有用約束建立的控件,就比較難以處理,我個人的意見是,做layer層的動畫,那上面的其他控件干脆也用frame布局。
POPAnimatableProperty *constantProperty = [POPAnimatableProperty propertyWithName:@"constant" initializer:^(POPMutableAnimatableProperty *prop){
prop.readBlock = ^(NSLayoutConstraint *layoutConstraint, CGFloat values[]) {
values[0] = [layoutConstraint constant];
};
prop.writeBlock = ^(NSLayoutConstraint *layoutConstraint, const CGFloat values[]) {
[layoutConstraint setConstant:values[0]];
};
}];
POPSpringAnimation *constantAnimation = [POPSpringAnimation animation];
constantAnimation.property = constantProperty;
constantAnimation.fromValue = @(_layoutConstraint.constant);
constantAnimation.toValue = @(200);
[_layoutConstraint pop_addAnimation:constantAnimation forKey:@"constantAnimation"];
以上就是一切使用問題的總結,詳細的使用可以參考源碼。