iOS 开发之使用 Facebook POP

作者: Erbash | 来源:发表于2018-10-01 23:27 被阅读277次

    需要打造游戏级别的动画效果?

    Facebook 开源的 POP 是一个在 iOS 与 OS X 上通用的极具扩展性的动画引擎,它在基本的静态动画的基础上增加的弹簧动画与衰减动画。

    POP 通过 CADisplayLink 将 APP 的重绘速度提高到跟屏幕刷新频率一致的 60 FPS !从而提供游戏级别的动画引擎,由此我们可以创造出更真实、更具物理性、更流畅的交互动画!

    没有对比就没有伤害,感兴趣的的同学可以看一下 纯洁的小袋子
    的“ Core Animation & Facebook's POP 对比” 。

    POP 的架构

    POP 目前由四部分组成:

    • Animations
    • Engine
    • Utility
    • WebCore
    Facebook POP

    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
    kCAMediaTimingFunctionLinear
    • kCAMediaTimingFunctionEaseIn
    kCAMediaTimingFunctionEaseIn
    • kCAMediaTimingFunctionEaseOut
    kCAMediaTimingFunctionEaseOut
    • kCAMediaTimingFunctionEaseInEaseOut
    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 是物质的弹性系数,它只由材料的性质所决定,与其他因素无关。负号表示弹簧所产生的弹力与其伸长(或压缩)的方向相反。

    Spring DECAY

    示例

    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

    五步使用 Facebook Pop

    五步使用 Facebook Pop

    Facebook Pop 动画框架详细解析

    Facebook Pop 源码注释

    从 CoreAnimation 到 POP

    缓动函数速查表

    iOS 核心动画高级技巧

    最后

    POP 是一个新的里程碑,通过 POP,动画的开发门槛大大降低,并且实现了丰富的属性操作,其倡导的可中断式动画交互会革命性也值得我们仔细研究体会,想必不久就会涌现大量富有活力的 App ,感谢 Facebook,感谢开源。 Long live Opensource


    内容来自于 丶纳凉里脊串Cocoachina 的博客

    相关文章

      网友评论

        本文标题:iOS 开发之使用 Facebook POP

        本文链接:https://www.haomeiwen.com/subject/ieynoftx.html