Pop上手體驗(i-v)

Pop上手體驗(i)html

Facebook一直爲開發者提供本身的開源代碼庫很是使人感激。最新的一個是Pop,在Github上不到24小時就已經得到3500個星了(目前是將近6000個)。git

 (文中涉及動態圖,可能會加載的慢,請耐心查看!)github

 

Facebook官方闡述:spring

 Pop是一個適用於iOS和OS X平臺的可擴展動畫引擎。除了基本的靜態動畫,Pop還支持spring和decay動畫,有助於打造一個逼真的,基於物理的交互。你能夠經過Pop的API把Pop快速集成到現有的Objective-C代碼庫中,並在任何對象上實現動畫的任何屬性。這是一個成熟的而且通過良好測試的框架,承載了Paper中全部的動畫和交互。

 

我使用Pop建立一個很是簡單的例子。我只是想看看它是如何很好地實現用戶輸入框帶有的陰影效果,它確實作得很棒。我還想快速的建立我所知道的東西。在使用POPSpringAnimation這個例子中,我以爲這個代碼跟我寫過的其餘代碼很類似。app

 

至於研究這個庫,個人策略是查閱這些文件中的.h文件(這庫也有Objective-C++版本):框架

POPBasicAnimationide

POPDecayAnimation測試

POPPropertyAnimation動畫

POPSpringAnimationui

POPCustomAnimation

POPAnimation

POPAnimatableProperty

 

Pop的一些東西確實很酷,即當你添加一個動畫時,展現層和模型層是同步的。Sam Page(@sampage)中使用Pop的圓圈例子就是這樣。因爲strokeEnd和strokeStart不是默認屬性的一部分,因此你須要建立本身的自定義屬性(不過我可能錯失了什麼),以下:

[POPAnimatableProperty propertyWithName:@"strokeStart" initializer:^(POPMutableAnimatableProperty *prop) {         prop.readBlock = ^(id obj, CGFloat values[]) {             values[0] = [obj strokeStart];         };         prop.writeBlock = ^(id obj, const CGFloat values[]) {             [obj setStrokeStart:values[0]];         };     }];

 

不得不說這個很強大,正如我以前所說的:表現層和模型層是同步的。

 

Pop上手體驗(ii)

Facebook Paper Tech Talk中讓我困惑的是Brian Amerige(@brianamerige)的一些話,尤爲是他向咱們示範如何跨過手勢和動畫之間的間隙(@ minute 47:40)。直接從視頻中得到的信息:

 基於手勢速度旋轉UIView:

- (void)rotate:(UIPanGestureRecognizer*)recognizer {     CGPoint velocity = [recognizer velocityInView:self.view];      POPSpringAnimation *spring = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerRotation];     spring.velocity = [NSValue valueWithCGPoint:velocity];      [_outletView.layer pop_addAnimation:spring forKey:@"rotationAnimation"]; }

 

如今,當你開始上手體驗時一切變得很是有趣:

 

當位置、大小和"dynamics"一同做用的時候會發生怎樣的事情?

代碼:

- (void)rotate:(UIPanGestureRecognizer*)recognizer {     CGPoint velocity = [recognizer velocityInView:self.view];  POPSpringAnimation *positionAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];   positionAnimation.velocity = [NSValue valueWithCGPoint:velocity];   positionAnimation.dynamicsTension = 5;   positionAnimation.dynamicsFriction = 5.0f;   positionAnimation.springBounciness = 20.0f;   [_outletView.layer pop_addAnimation:positionAnimation forKey:@"positionAnimation"];   POPSpringAnimation *sizeAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerSize];   sizeAnimation.velocity = [NSValue valueWithCGPoint:velocity];   sizeAnimation.springBounciness = 1.0f;   sizeAnimation.dynamicsFriction = 1.0f;   [_outletView.layer pop_addAnimation:sizeAnimation forKey:@"sizeAnimation"]; }

 

移除與"dynamics"相關的代碼後:

你仍然能看到輕微的彈跳效果,但這是POPSpringAnimation的默認值。

  

Pop上手體驗(iii)

Pop或者任何其餘出於消遣目的的庫都會涉及到一點--我應該用它來作什麼?在Paper by Facebook這篇文章中,做者Brian Lovin (@brian_lovin)用動態圖展現了Paper的設計細節,能夠幫忙進行思考。下圖來自Brian Lovin的博客(這裏有該博客的譯文:23個Facebook Paper中的設計細節 ):

  

我想建立能夠展現小彈窗的東西,但還要帶一點震動效果(好吧,由於我喜歡)。這個描述可能不是很準確(甚至相差甚遠),但它給了我一點靈感,因此:

 

你也看的出來,它彷佛不是那麼迷人,可是用Pop很容易作出來。

- (void)hidePopup {     _isMenuOpen = NO;     POPBasicAnimation *opacityAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerOpacity];     opacityAnimation.fromValue = @(1);     opacityAnimation.toValue = @(0);     [_popUp.layer pop_addAnimation:opacityAnimation forKey:@"opacityAnimation"];      POPBasicAnimation *positionAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPosition];     positionAnimation.fromValue = [NSValue valueWithCGPoint:VisiblePosition];     positionAnimation.toValue = [NSValue valueWithCGPoint:HiddenPosition];     [_popUp.layer pop_addAnimation:positionAnimation forKey:@"positionAnimation"];      POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];      scaleAnimation.fromValue  = [NSValue valueWithCGSize:CGSizeMake(1.0f, 1.0f)];     scaleAnimation.toValue  = [NSValue valueWithCGSize:CGSizeMake(0.5f, 0.5f)];     [_popUp.layer pop_addAnimation:scaleAnimation forKey:@"scaleAnimation"]; }

 

展現:

- (void)showPopup {     _isMenuOpen = YES;      POPBasicAnimation *opacityAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerOpacity];     opacityAnimation.fromValue = @(0);     opacityAnimation.toValue = @(1);     opacityAnimation.beginTime = CACurrentMediaTime() + 0.1;     [_popUp.layer pop_addAnimation:opacityAnimation forKey:@"opacityAnimation"];      POPBasicAnimation *positionAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPosition];     positionAnimation.fromValue = [NSValue valueWithCGPoint:VisibleReadyPosition];     positionAnimation.toValue = [NSValue valueWithCGPoint:VisiblePosition];     [_popUp.layer pop_addAnimation:positionAnimation forKey:@"positionAnimation"];       POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];     scaleAnimation.fromValue  = [NSValue valueWithCGSize:CGSizeMake(0.5, 0.5f)];     scaleAnimation.toValue  = [NSValue valueWithCGSize:CGSizeMake(1.0f, 1.0f)];//@(0.0f);     scaleAnimation.springBounciness = 20.0f;     scaleAnimation.springSpeed = 20.0f;     [_popUp.layer pop_addAnimation:scaleAnimation forKey:@"scaleAnimation"]; }

 

三條注意事項:

1. 當添加相似[myView pop_addAnimation:animation forKey:@"animationKey"];的動畫時,若是你用相同的key添加其餘動畫,那麼新添加的動畫將會取代先前的動畫。

2. 當你想要開始一個動畫時,使用CACurrentMediaTime()生成一個動畫開始時間來初始化beginTime。因此它看起來應該像:animation.beginTimee = CACurrentMediaTime() + delayInSeconds;.我簡單地添加了delay,固然不會湊效。感謝Kimon(@kimon) 的警告。

3. 當你看到相似kPOPLayerScaleXY屬性時,它將會有兩個值。在這個例子中是CGSize。如今多是有意義的,不過我傳遞了一個NSNumber(單一值),期待設置成X和Y值。

 

Pop上手體驗(iv)

這是天才 (via @_tiagoalmeida):

 

還真有用:

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

 

感謝Jake Marsh (@jakemarsh).

 

這是一個小便籤,我沒有注意到kPOPLayoutConstraintConstant,因此你無需建立一個自定義POPAnimatableProperty。

  

Pop上手體驗 (v)

在上手體驗Pop幾天後,有一點就是除了享受它,我應該作一點貢獻。

 

在該系列的第一篇中,我爲strokeStart和strokeEnd (二者均屬於CAShapeLayer)建立了自定義屬性:

[POPAnimatableProperty propertyWithName:@"strokeStart" initializer:^(POPMutableAnimatableProperty *prop) {         prop.readBlock = ^(id obj, CGFloat values[]) {             values[0] = [obj strokeStart];         };         prop.writeBlock = ^(id obj, const CGFloat values[]) {             [obj setStrokeStart:values[0]];         };     }];

 

這個過程有點工做量,但不用懼怕。個人第一個pull request(但願不是最後一個)已經經過審覈,並併入了主要的Pop repo。這意味着如今我讓這兩個屬性應用在了CAShapeLayer上,沒有添加任何邏輯。

 

簡單幾步便可爲Pop添加屬性,若是有人想要貢獻的話,能夠:

1.把NSString和你的屬性名稱添加到POPAnimatableProperty.h中,遵照它的命名慣例,看起來可能像kPOP<class name witout prefix><propertyName>。若是它不止有一個值,那麼它可能會像kPOP<class name witout prefix><propertyName>XY。而後在POPAnimatableProperty.m上添加實際值,它可能會是NSString * const kPop<class name witout prefix><propertyName> = @"<propertyName>"。若是你不肯定如何命名,能夠看看其餘屬性。

2.添加write/read blocks有效的方法,加上閥值。你能夠看看其餘屬性是怎麼作的

3.我不須要這麼作,由於我添加的屬性很是簡單。當讀/寫新值的時候,充分利用輔助屬性會好不少。好比你能夠看看kPOPViewBackgroundColor是如何實現的:

{kPOPViewBackgroundColor,   ^(UIView *obj, CGFloat values[]) {     POPUIColorGetRGBAComponents(obj.backgroundColor, values);   },   ^(UIView *obj, const CGFloat values[]) {     obj.backgroundColor = POPUIColorRGBACreate(values);   },   1.0 },

 

這個例子使用了POPUIColorGetRGBAComponents和POPUIColorRGBACreate:

void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[])   {   return POPCGColorGetRGBAComponents(color.CGColor, components); }  UIColor *POPUIColorRGBACreate(const CGFloat components[])   {   CGColorRef colorRef = POPCGColorRGBACreate(components);   UIColor *color = [[UIColor alloc] initWithCGColor:colorRef];   CGColorRelease(colorRef);   return color; }

 

這個輔助方法位於POPCGUtils上,雖然POPLayerExtras上有不少。做爲一個「良好公民」,你能夠建立其餘方法,因此用戶可把它們用於其餘類似的屬性行爲。

1. 爲test suit添加你的屬性!因爲那些屬性闇昧不明,因此我僅把它添加到了POPAnimatablePropertyTests.m的testProvidedExistence,以確保它的實現是確實存在的。

2. 若是你作了不同凡響的事情,而且沒有覆蓋默認的test suit,那麼你須要更多的測試。

 

隨着個人需求的增加,我將會爲Pop貢獻更多。

 

原文:

Playing with Pop (i) 

Playing with Pop (ii)

Playing with Pop (iii)

Playing with pop (iv)

Playing with pop (v)

 

推薦閱讀:

優秀開源項目:Facebook Paper動畫引擎--Pop

Facebook 開源旗下閱讀應用Paper背後的動畫引擎

23個Facebook Paper中的設計細節

相關文章
相關標籤/搜索