文档章节

Pop上手体验(i-v)

m
 mingxun
发布于 2014/05/07 13:15
字数 1909
阅读 148
收藏 6
点赞 0
评论 0

Pop上手体验(i)

Facebook一直为开发者提供自己的开源代码库非常令人感激。最新的一个是Pop,在Github上不到24小时就已经获得3500个星了(目前是将近6000个)。

 (文中涉及动态图,可能会加载的慢,请耐心查看!)

 

Facebook官方阐述:

 Pop是一个适用于iOS和OS X平台的可扩展动画引擎。除了基本的静态动画,Pop还支持spring和decay动画,有助于打造一个逼真的,基于物理的交互。你可以通过Pop的API把Pop快速集成到现有的Objective-C代码库中,并在任何对象上实现动画的任何属性。这是一个成熟的并且经过良好测试的框架,承载了Paper中所有的动画和交互。

 

我使用Pop创建一个非常简单的例子。我只是想看看它是如何很好地实现用户输入框带有的阴影效果,它确实做得很棒。我还想快速的创建我所知道的东西。在使用POPSpringAnimation这个例子中,我觉得这个代码跟我写过的其他代码很相似。

 

至于研究这个库,我的策略是查阅这些文件中的.h文件(这库也有Objective-C++版本):

POPBasicAnimation

POPDecayAnimation

POPPropertyAnimation

POPSpringAnimation

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


本文转载自:http://www.cocoachina.com/applenews/devnews/2014/0507/8339.html

共有 人打赏支持
m
粉丝 3
博文 138
码字总数 9074
作品 0
崇明
破解5.0版TKScope不支持Keil下使用CK100调试TinyM0(仅供测试,请使用正版软件)

准备做个RFID的测试工程,找到了以前用过的TinyM0。 以前一直使用Tao宝来的山寨JLink V 8。但是发现调试起来要接4根杜邦线,还得带个仿真器的线和盒子,实在是不方便。为什么不用自带的CK100...

bygreencn
2014/01/02
0
0
设计数据结构SetOfStacks, 由多个栈组成,并且在前一个栈填满时新建一个栈

设想有一堆盘子,堆太高可能会倒下来。因此,现实生活中,盘子堆到一定高度时,我们就会另外堆一堆盘子。请事先设计数据结构SetOfStacks, 模拟这种行为。 SetOfStacks应该由多个栈组成,并且...

一贱书生
2016/11/17
3
0
System76 要为自家的 Pop!_OS 发行版提供全盘加密功能

知名 Linux PC 制造商 System76 和我们分享了 Linux 发行版 Pop!OS 下一个版本的一些更新细节。Pop!OS 是 System76 自家的首个 GNU/Linux 发行版,基于 Canonical 的 Ubuntu。 看起来,Syste...

局长
01/30
0
2
在没有DOM操作的日子里,我是怎么熬过来的(上)

前言 在我动笔写这篇文章的时候,我刚刚从我的项目中删除了最后一行JQuery代码。至于我为何要这么做,请听闰土娓娓道来。前几年我还在想,假如有一天,前端世界里不能再直接操作dom了,我该怎...

闰土少年
2017/11/28
0
0
使用javap分析return和finally的执行字节码

常见指令: 1、putstatic #5; --putstatic当栈顶元素出栈放到常量解析池中的#5位置 2、iconst1 --int常量1放入操作数栈 3、aload0 --将局部变量0位置对象取出来,压入栈push 4、invokespecial...

墙头草
2011/09/16
0
0
SwiftySideMenu

SwiftySideMenu 是一个轻量级完全可定制,而且易用的边栏菜单,基于 Pop-scale 动画效果。动画使用 Pop 框架提供了平滑、智能的动画体验。可用于 Objective-C 和 Swift 项目。...

hossamghareeb
2015/08/30
873
0
Python3基础-列表方法

列表元素添加 append() 列表元素追加 【整体追加】参数整体 extend() 列表元素追加 【元素扩展循环追加】参数可迭代对象 insert() 指定索引位置插入元素 copy() 列表浅拷贝 列表元素索引统计...

ZHAO_JH
03/06
3
0
保存最小值得栈 Min Stack

问题: Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. push(x) -- Push element x onto stack. pop() -- Removes the element on to......

叶枫啦啦
2017/08/16
0
0
Microsoft Project Honolulu上手体验

2017年9月22日,微软宣布Technical Preview Project Honolulu,邀请广大IT人士一起下载测试,老王也跟着凑了个热闹 记得在16年的时候微软在Azure上面TP了一个Azure SMT serive ,不知道是否还...

老收藏家
2017/09/24
0
0
一套代码iOS、Android两端运行,Google Flutter意味着什么?

作者 | 屠敏 一套代码可支持 Android 和 iOS 双端运行,你 Get 了吗? 它就是 Flutter。其目标是为了解决移动中的两个重要问题:一是实现原生应用的性能和与平台的集成,二是提供一个多平台,...

终端研发部
06/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

217. Contains Duplicate - LeetCode

Question 217. Contains Duplicate Solution 题目大意:判断数组中是否有重复元素 思路:构造一个set,不重复就加进去,重复返回true,如果数据量大的话,可以用布隆过滤器 Java实现: publ...

yysue
2分钟前
0
0
istio 处理失败

Envoy提供了一套开箱即用的选择加入故障恢复功能,可以通过应用程序中的服务进行利用。功能包括: 超时 具有超时预算和重试之间的可变抖动的有界重试 限制并发连接数和对上游服务的请求 对负...

xiaomin0322
3分钟前
0
0
eclipse解决git冲突举例

本地修改了两个文件,提交时提示有冲突,想来应该是没有从远程仓库下载最新代码导致的。通过右击项目 -> Team -> Sychronized WorkSpace,比较本地仓库和远程仓库的异同:   此时没有更好的...

Code辉
11分钟前
0
0
运行.jar后缀的文件

前提必须安装了jdk,正确配置环境变量。 在dos窗口执行以下命令即可。 java -jar C:\Users\10492\Desktop\turn.jar

haha360
14分钟前
0
0
Java程序员如何做代码压力测试?【JWordPress前台项目实战】

代码 pom.xml文件引入包 <dependency><groupId>com.taobao.stresstester</groupId><artifactId>stresstester</artifactId><version>1.0</version></dependency> 编写测试代码 /**......

迷你芊宝宝
19分钟前
0
0
面试宝典-什么是缓存穿透?

缓存穿透是说收到了一个请求,但是该请求缓存里没有,只能去数据库里查询,然后放进缓存。 这里面有两个风险,一个是同时有好多请求访问同一个数据,然后业务系统把这些请求全发到了数据库;...

suyain
24分钟前
0
0
vue基础知识练习2

一、发送AJAX请求 <div id="demo1"><button @click="send">发送AJAX请求</button><button @click="sendGet">GET方式发送AJAX请求</button><button @click="sendPost">POST方式发送A......

一个yuanbeth
27分钟前
0
0
Xamarin Essentials教程磁力计Magnetometer

Xamarin Essentials教程磁力计Magnetometer 磁力计也叫地磁、磁感器,可用于测试磁场强度和方向。在手持设备中,通过磁力计可以计算设备的左右、前后倾斜角度,广泛应用于手机各种的应用中。...

大学霸
31分钟前
0
0
mesos:Authentication timed out

最近当slave开始慢慢部署异地集群的时候又碰上了这个问题 I0717 10:27:11.695762 28852 slave.cpp:895] New master detected at master@192.168.2.161:5050I0717 10:27:11.695811 28852 sl......

xueyi28
38分钟前
0
0
赋予用户库的读写权限

1、创建用户 CREATE USER 'test'@'%' IDENTIFIED BY '15ht46389012t'; #'%' - 所有情况都能访问;‘localhost’ - 本机才能访问;’192.168.1.2‘ - 指定 ip 才能访问 2、赋予权限 grant al...

xixingzhe
38分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部