需要打造游戏级别的动画效果?
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
#import
#import
@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
@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)
@end
基本动画类 POPBasicAnimation
#import
/**
基础动画
*/
@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
/**
弹簧动画类;通过弹簧动力学模型实现动画
*/
@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
/**
衰减动画,也有称阻尼动画
*/
@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
@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
#import
@class POPMutableAnimatableProperty;
/**
描述动画属性
*/
@interface POPAnimatableProperty : NSObject
/**
根据名字创建动画属性,名字不存在 = 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
#import
/**
@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
五步使用 Facebook Pop
五步使用 Facebook Pop
Facebook Pop 动画框架详细解析
Facebook Pop 源码注释
从 CoreAnimation 到 POP
缓动函数速查表
iOS 核心动画高级技巧
最后
POP 是一个新的里程碑,通过 POP,动画的开发门槛大大降低,并且实现了丰富的属性操作,其倡导的可中断式动画交互会革命性也值得我们仔细研究体会,想必不久就会涌现大量富有活力的 App ,感谢 Facebook,感谢开源。 Long live Opensource
内容来自于 丶纳凉 、里脊串 、Cocoachina 的博客