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中的设计细节

相关文章
相关标签/搜索