iOS 开发之使用 Facebook POP
需要打造游戏级别的动画效果?
Facebook 开源的 POP 是一个在 iOS 与 OS X 上通用的极具扩展性的动画引擎,它在基本的静态动画的基础上增加的弹簧动画与衰减动画。
POP 通过 CADisplayLink 将 APP 的重绘速度提高到跟屏幕刷新频率一致的 60 FPS !从而提供游戏级别的动画引擎,由此我们可以创造出更真实、更具物理性、更流畅的交互动画!
没有对比就没有伤害,感兴趣的的同学可以看一下 纯洁的小袋子
的“ Core Animation & Facebook's POP 对比” 。
POP 的架构
POP 目前由四部分组成:
- Animations
- Engine
- Utility
- WebCore
WebCore 里包含了一些从 Apple 的开源的网页渲染引擎里拿出的源文件,与 Utility 里的组件一并,提供了 POP 的各项复杂计算的基本支持。
由此通过 Engine、Utility、WebCore 三个基石,打造了Animations。
POP 提供的动画类
- POPAnimation(动画的抽象基类)
- POPBasicAnimation (基本动画类)
- POPSpringAnimation (弹性动画类)
- POPDecayAnimation (衰减动画类)
- POPCustomAnimation (自定义动画类)
- POPAnimatableProperty (自定义属性动画)
- POPPropertyAnimation(自定义属性动画)
动画的抽象基类 POPAnimation
#import <Foundation/NSObject.h> #import <pop/POPAnimationTracer.h> #import <pop/POPGeometry.h> @class CAMediaTimingFunction; /** 动画的抽象基类. */ @interface POPAnimation : NSObject /** 动画的名称 根据这个属性用来区别动画;识别动画 */ @property (copy, nonatomic) NSString *name; /** 动画的开始时间; 默认是从0开始启动 */ @property (assign, nonatomic) CFTimeInterval beginTime; /** 动画的 delegate 详情查看查看[POPAnimationDelegate] */ @property (weak, nonatomic) id delegate; /** 动画的追踪器 记录所有动画相关事件,还允许完成后对其进行查询和分析;更多可以查看 [POPAnimationTracer.h] */ @property (readonly, nonatomic) POPAnimationTracer *tracer; /** 动画开始的时候回调的block */ @property (copy, nonatomic) void (^animationDidStartBlock)(POPAnimation *anim); /** 动画达到toValue或者超过值的时候调用的block */ @property (copy, nonatomic) void (^animationDidReachToValueBlock)(POPAnimation *anim); /** 动画完成的时候调用的block */ @property (copy, nonatomic) void (^completionBlock)(POPAnimation *anim, BOOL finished); /** 正在做动画的时候调用;调用次数比较多 */ @property (copy, nonatomic) void (^animationDidApplyBlock)(POPAnimation *anim); /** 完成动画的时候是否删除动画; 默认为YES; 设置NO的话 */ @property (assign, nonatomic) BOOL removedOnCompletion; /** 动画是否已暂停; 在初始化的时候,默认YES;在动画添加的时候,隐式暂停???在动画完成的时候和 removedOnCompletion = NO 的时候,动画是暂停的; */ @property (assign, nonatomic, getter = isPaused) BOOL paused; /** 动画是否逆转;比如向前的动画,做完之后,会再后退回来; 注意:时间是原来的 2 倍,动画到 toValue 后,又回到原始的值; delegate 跟再做一次动画一样; */ @property (assign, nonatomic) BOOL autoreverses; /** 重复动画次数; = 0 或者 1 不会重复; 注意: delegate 中 animationDidStart:每次动画重复开头调用; animationDidReachToValue:每次到 toValue 的时候调用; animationDidStop:finished:每次到 toValue 的时候调用,如果设置了 autoreverses,动画还未完成,返回 NO; 设置了 autoreverses,动画时间是原来 2 倍; */ @property (assign, nonatomic) NSInteger repeatCount; /** 一直重复做动画; delegate 中 animationDidStop 将恒等于 NO; */ @property (assign, nonatomic) BOOL repeatForever; @end @protocol POPAnimationDelegate <NSObject> @optional /** 动画开始的时候调用 */ - (void)pop_animationDidStart:(POPAnimation *)anim; /** 动画达到toValue或者超过的时候调用; */ - (void)pop_animationDidReachToValue:(POPAnimation *)anim; /** 动画停止 */ - (void)pop_animationDidStop:(POPAnimation *)anim finished:(BOOL)finished; /** 正在做动画的时候调用; */ - (void)pop_animationDidApply:(POPAnimation *)anim; @end @interface NSObject (POP) /** 添加动画到接收器; anim:要添加的动画 key:动画标识符,可以是任何字符串,但每个动画必须唯一; */ - (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key; /** 删除所有附件在接收器上的动画; */ - (void)pop_removeAllAnimations; /** 删除附加在接收器上的所有关键 */ - (void)pop_removeAnimationForKey:(NSString *)key; /** 返回接收器所有动画的 key 的数组;key 的顺序 = 动画顺序; */ - (NSArray *)pop_animationKeys; /** 返回某个 key 的动画,= nil 表示不存在 */ - (id)pop_animationForKey:(NSString *)key; @end /** 实现NSCopying协议; */ @interface POPAnimation (NSCopying) <NSCopying> @end
基本动画类 POPBasicAnimation
#import <pop/POPPropertyAnimation.h> /** 基础动画 */ @interface POPBasicAnimation : POPPropertyAnimation /** 类创建实例 */ + (instancetype)animation; /** 指定属性动画; */ + (instancetype)animationWithPropertyNamed:(NSString *)name; /** 使用 kCAMediaTimingFunctionDefault 定时功能的基本动画; */ + (instancetype)defaultAnimation; /** @使用 kCAMediaTimingFunctionLinear 定时功能的基本动画; */ + (instancetype)linearAnimation; /** @使用 kCAMediaTimingFunctionEaseIn 定时功能的基本动画; */ + (instancetype)easeInAnimation; /** @使用 kCAMediaTimingFunctionEaseOut 定时功能的基本动画; */ + (instancetype)easeOutAnimation; /** @使用 kCAMediaTimingFunctionEaseIn 定时功能的基本动画; */ + (instancetype)easeInEaseOutAnimation; /** 延迟多少秒执行动画:Defaults to 0.4. */ @property (assign, nonatomic) CFTimeInterval duration; /** 设置动画节奏,默认使用:kCAMediaTimingFunctionDefault CA_EXTERN NSString * const kCAMediaTimingFunctionLinear CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0); CA_EXTERN NSString * const kCAMediaTimingFunctionEaseIn CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0); CA_EXTERN NSString * const kCAMediaTimingFunctionEaseOut CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0); CA_EXTERN NSString * const kCAMediaTimingFunctionEaseInEaseOut CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0); CA_EXTERN NSString * const kCAMediaTimingFunctionDefault CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0); */ @property (strong, nonatomic) CAMediaTimingFunction *timingFunction; @end
POPBasicAnimation 提供的四种 TimingFunction
- kCAMediaTimingFunctionLinear
- kCAMediaTimingFunctionEaseIn
- kCAMediaTimingFunctionEaseOut
- kCAMediaTimingFunctionEaseInEaseOut
示例
POPBasicAnimation * butAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter]; butAnimation.duration = 1.0f; butAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(_btn.centerX,_btn.centerY + 400)]; [_btn pop_addAnimation:butAnimation forKey:@"btn_Animation"];
弹性动画类 POPSpringAnimation
#import <pop/POPPropertyAnimation.h> /** 弹簧动画类;通过弹簧动力学模型实现动画 */ @interface POPSpringAnimation : POPPropertyAnimation /** 初始化一个实例 */ + (instancetype)animation; /** 指定属性动画的实例 */ + (instancetype)animationWithPropertyNamed:(NSString *)name; /** 当前速度; 做动画开始之前应该设置初始速度; */ @property (copy, nonatomic) id velocity; /** 反弹力度 范围 [0, 20],默认 4. */ @property (assign, nonatomic) CGFloat springBounciness; /** 速度 范围 [0, 20]. 默认 to 12. */ @property (assign, nonatomic) CGFloat springSpeed; /** 拉力 影响回弹力度以及速度 值越大,动画速度越快 */ @property (assign, nonatomic) CGFloat dynamicsTension; /** 摩擦力 如果开启,动画会不断重复,幅度逐渐削弱,直到停止。 */ @property (assign, nonatomic) CGFloat dynamicsFriction; /** 质量 细微的影响动画的回弹力度以及速度 */ @property (assign, nonatomic) CGFloat dynamicsMass; @end
- 胡克定义
F=-k·x
表达式为 F=-k·x 或 F=-k·Δx ,弹簧的弹力F和弹簧的伸长量(或压缩量)x 成正比,即 F= k·x 。k 是物质的弹性系数,它只由材料的性质所决定,与其他因素无关。负号表示弹簧所产生的弹力与其伸长(或压缩)的方向相反。
示例
POPSpringAnimation *springAnimaiton = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionY]; springAnimaiton.toValue = @(500); [_btn pop_addAnimation:springAnimaiton forKey:@"springAnimation"]; springAnimaiton.springBounciness = 20; springAnimaiton.springSpeed = 20;
以下这 3 个比较难用;如果不是特别需求,springBounciness 和 springSpeed 就可以解决问题;
// springAnimaiton.dynamicsTension = _value1; // springAnimaiton.dynamicsFriction = _value2; // springAnimaiton.dynamicsMass = _value3;
衰减动画类 POPDecayAnimation
#import <pop/POPPropertyAnimation.h> /** 衰减动画,也有称阻尼动画 */ @interface POPDecayAnimation : POPPropertyAnimation /** 实例对象 */ + (instancetype)animation; /** 指定属性动画的实例 */ + (instancetype)animationWithPropertyNamed:(NSString *)name; /** 初始速度; 支持: kPOPValuePoint, kPOPValueInteger, kPOPValueFloat, kPOPValueRect, kPOPValueSize; */ @property (copy, nonatomic) id velocity; /** 原始速度 用于设置 autoreverse 和 repeatCount */ @property (copy, nonatomic, readonly) id originalVelocity; /** 减速:较低的值会更快的减速 范围[0, 1]. 默认 0.998. */ @property (assign, nonatomic) CGFloat deceleration; /** 预计持续时间; 根据 velocity 和 deceleration 得出 */ @property (readonly, assign, nonatomic) CFTimeInterval duration; /** 基于Velocity 和 deceleration; */ - (void)setToValue:(id)toValue NS_UNAVAILABLE; /** 反转速度 */ - (id)reversedVelocity; @end
示例
POPDecayAnimation *anim = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPositionY]; anim.velocity = @(300); [_btn pop_addAnimation:anim forKey:@"slide"];
自定义动画 POPCustomAnimation
#import <pop/POPAnimation.h> @class POPCustomAnimation; /** 是自定义动画的回调块 每个帧动画回调此 block,最新的属性; target:动画对象,避免循环; animation:动画实例,确定上次回调来的当前时间,和已经使用的时间;避免循环使用; return no = 动画完成; */ typedef BOOL (^POPCustomAnimationBlock)(id target, POPCustomAnimation *animation); /** 自定义动画 */ @interface POPCustomAnimation : POPAnimation /** 初始化,并返回一个动画实例 */ + (instancetype)animationWithBlock:(POPCustomAnimationBlock)block; /** 当前动画的时间 */ @property (readonly, nonatomic) CFTimeInterval currentTime; /** 上次回调的时间 */ @property (readonly, nonatomic) CFTimeInterval elapsedTime; @end
自定义属性动画 POPAnimatableProperty
#import <CoreGraphics/CoreGraphics.h> #import <Foundation/NSObject.h> @class POPMutableAnimatableProperty; /** 描述动画属性 */ @interface POPAnimatableProperty : NSObject <NSCopying, NSMutableCopying> /** 根据名字创建动画属性,名字不存在 = nil; */ + (id)propertyWithName:(NSString *)name; /** 根据名字创建动画属性,名字不存在 = nil; 如果名字存在,则初始化 block 实例; */ + (id)propertyWithName:(NSString *)name initializer:(void (^)(POPMutableAnimatableProperty *prop))block; /** 属性的名字,标识唯一动画属性 */ @property (readonly, nonatomic, copy) NSString *name; /** 返回当前属性值 */ @property (readonly, nonatomic, copy) void (^readBlock)(id obj, CGFloat values[]); /** 修改变化的值 */ @property (readonly, nonatomic, copy) void (^writeBlock)(id obj, const CGFloat values[]); /** 决定动画变化的间隔的阈(yu第四声)值;值越大,writeBlock 的调用次数越少; */ @property (readonly, nonatomic, assign) CGFloat threshold; @end /** 可变动画可变属性; */ @interface POPMutableAnimatableProperty : POPAnimatableProperty /** 属性的名称 */ @property (readwrite, nonatomic, copy) NSString *name; /** 返回当前属性值 */ @property (readwrite, nonatomic, copy) void (^readBlock)(id obj, CGFloat values[]); /** 修改变化的值 */ @property (readwrite, nonatomic, copy) void (^writeBlock)(id obj, const CGFloat values[]); /** 决定动画变化的间隔的阈(yu第四声)值;值越大,writeBlock的调用次数越少; */ @property (readwrite, nonatomic, assign) CGFloat threshold; @end /** 常见的 CALayer 属性名称 */ extern NSString * const kPOPLayerBackgroundColor; extern NSString * const kPOPLayerBounds; extern NSString * const kPOPLayerCornerRadius; extern NSString * const kPOPLayerBorderWidth; extern NSString * const kPOPLayerBorderColor; extern NSString * const kPOPLayerOpacity; extern NSString * const kPOPLayerPosition; extern NSString * const kPOPLayerPositionX; extern NSString * const kPOPLayerPositionY; extern NSString * const kPOPLayerRotation; extern NSString * const kPOPLayerRotationX; extern NSString * const kPOPLayerRotationY; extern NSString * const kPOPLayerScaleX; extern NSString * const kPOPLayerScaleXY; extern NSString * const kPOPLayerScaleY; extern NSString * const kPOPLayerSize; extern NSString * const kPOPLayerSubscaleXY; extern NSString * const kPOPLayerSubtranslationX; extern NSString * const kPOPLayerSubtranslationXY; extern NSString * const kPOPLayerSubtranslationY; extern NSString * const kPOPLayerSubtranslationZ; extern NSString * const kPOPLayerTranslationX; extern NSString * const kPOPLayerTranslationXY; extern NSString * const kPOPLayerTranslationY; extern NSString * const kPOPLayerTranslationZ; extern NSString * const kPOPLayerZPosition; extern NSString * const kPOPLayerShadowColor; extern NSString * const kPOPLayerShadowOffset; extern NSString * const kPOPLayerShadowOpacity; extern NSString * const kPOPLayerShadowRadius; /** 常见的 CAShapeLayer 属性名称 */ extern NSString * const kPOPShapeLayerStrokeStart; extern NSString * const kPOPShapeLayerStrokeEnd; extern NSString * const kPOPShapeLayerStrokeColor; extern NSString * const kPOPShapeLayerFillColor; /** 常见的 NSLayoutConstraint 属性名称 */ extern NSString * const kPOPLayoutConstraintConstant; #if TARGET_OS_IPHONE /** 常见的 UIView 属性名称 */ extern NSString * const kPOPViewAlpha; extern NSString * const kPOPViewBackgroundColor; extern NSString * const kPOPViewBounds; extern NSString * const kPOPViewCenter; extern NSString * const kPOPViewFrame; extern NSString * const kPOPViewScaleX; extern NSString * const kPOPViewScaleXY; extern NSString * const kPOPViewScaleY; extern NSString * const kPOPViewSize; extern NSString * const kPOPViewTintColor; /** 常见的 UIScrollView 属性名称 */ extern NSString * const kPOPScrollViewContentOffset; extern NSString * const kPOPScrollViewContentSize; extern NSString * const kPOPScrollViewZoomScale; extern NSString * const kPOPScrollViewContentInset; /** 常见的 UITableView 属性名称 */ extern NSString * const kPOPTableViewContentOffset; extern NSString * const kPOPTableViewContentSize; /** 常见的 UICollectionView 属性名称 */ extern NSString * const kPOPCollectionViewContentOffset; extern NSString * const kPOPCollectionViewContentSize; /** 常见的 UINavigationBar 属性名称 */ extern NSString * const kPOPNavigationBarBarTintColor; /** 常见的 UIToolbar 属性名称 */ extern NSString * const kPOPToolbarBarTintColor; /** 常见的 UITabBar 属性名称 */ extern NSString * const kPOPTabBarBarTintColor; /** 常见的 UILabel 属性名称 */ extern NSString * const kPOPLabelTextColor;
自定义属性动画 POPPropertyAnimation
#import <pop/POPAnimatableProperty.h> #import <pop/POPAnimation.h> /** @abstract Flags for clamping animation values. @discussion Animation values can optionally be clamped to avoid overshoot. kPOPAnimationClampStart ensures values are more than fromValue and kPOPAnimationClampEnd ensures values are less than toValue. */ typedef NS_OPTIONS(NSUInteger, POPAnimationClampFlags) { kPOPAnimationClampNone = 0, kPOPAnimationClampStart = 1UL << 0, kPOPAnimationClampEnd = 1UL << 1, kPOPAnimationClampBoth = kPOPAnimationClampStart | kPOPAnimationClampEnd, }; /** semi-concrete 属性动画子类 */ @interface POPPropertyAnimation : POPAnimation /** 做动画的属性 */ @property (strong, nonatomic) POPAnimatableProperty *property; /** 做动画的初始值; 如果未设置,则在动画启动的时候,按照对象当前的值作为初始值; */ @property (copy, nonatomic) id fromValue; /** 做动画的值 如果未设置,则在动画启动的时候,按照对象当前的值作为初始值; */ @property (copy, nonatomic) id toValue; /** 四舍五入系数; 作用让动画变得更圆滑; 默认0; 取1.0和取整值之间; */ @property (assign, nonatomic) CGFloat roundingFactor; /** 就是让动画保证在fromValue和tovalue之间,不会越界; */ @property (assign, nonatomic) NSUInteger clampMode; /** 动画的值是叠加,而不是设置; 默认 NO; */ @property (assign, nonatomic, getter = isAdditive) BOOL additive; @end
值得关注的 POP 周边
POP-HandApp 包含了大量动画的操作方法和上述介绍的实例。
AGGeometryKit-POP 通过 POP 对图片进行变形操作,非常酷。
POP-MCAnimate POP 的一个封装,可以让你更方便的使用 POP。
Rebound POP 的 Android 部分实现,主要是 Spring 的效果,移植自 Facebook 的rebound-js。
5 Steps For Using Facebook Pop
最后
POP 是一个新的里程碑,通过 POP,动画的开发门槛大大降低,并且实现了丰富的属性操作,其倡导的可中断式动画交互会革命性也值得我们仔细研究体会,想必不久就会涌现大量富有活力的 App ,感谢 Facebook,感谢开源。 Long live Opensource
内容来自于 丶纳凉 、里脊串 、Cocoachina 的博客

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
如何使用WorkManager执行后台任务(下)
0x00 WorkManager的高级用法 在上一文中已经了解到 WorkManager的基本用法之后,今天来看看它的一些高级用法: 链式任务调用 唯一任务序列 传递参数和获取返回值 0x01 链式任务(Chained tasks) WorkManager在执行多个工作任务的时候,可以指定执行顺序。假设一个应用程序中有3个 OneTimeWorkRequest对象: workA、 workB、 workC。这几个任务需要按照顺序执行,那么可以使用 WorkManager.beginWith()方法加入 workA,这时候会返回一个 WorkContinuation对象,它定义了工作任务的执行序列。然后通过它再调用 WorkContinuation.then()把 workB和 workC加入到执行队列中,最后执行 WorkManager.enqueue()方法。 WorkManager.getInstance() .beginWith(workA) // Note: WorkManager.beginWith() returns a // WorkContinuation object...
- 下一篇
Material Design 实战 之第四弹 —— 卡片布局以及灵动的标题栏(CardView & AppBarLayout)
本模块共有六篇文章,参考郭神的《第一行代码》,对Material Design的学习做一个详细的笔记,大家可以一起交流一下: Material Design 实战 之第一弹——Toolbar(即本文) Material Design 实战 之第二弹——滑动菜单详解&实战 Material Design 实战 之第三弹—— 悬浮按钮和可交互提示(FloatingActionButton & Snackbar & CoordinatorLayout) Material Design 实战 之第四弹 —— 卡片布局以及灵动的标题栏(CardView & AppBarLayout) Material Design 实战 之第五弹 —— 下拉刷新(SwipeRefreshLayout) Material Design 实战 之 第六弹 —— 可折叠式标题栏(CollapsingToolbarLayout) & 系统差异型的功能实现(充分利用系统状态栏空间) 卡片式布局也是MaterialsDesign中提出的一个新的概念,它可以让页面中的元素看起来就像在卡...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS关闭SELinux安全模块
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2更换Tomcat为Jetty,小型站点的福音