• POP介绍与使用实践(快速上手动画)


    http://adad184.com/2015/03/11/intro-to-pop/

    前言


    动画在APP开发过程中 大家多多少少都会接触到 而且随着ios7的扁平化风格启用之后 越来越多的APP开始尝试加入各种绚丽的动画交互效果以增加APP的用户体验(当然 还是以国外的APP居多)

    有过相关开发经验的同学肯定知道在iOS中 动画相关的部分都是基于Core Animation 但是今天我们不讨论Core Animation 今天的主角是POP -来自于Facebook的动画引擎(其实我不喜欢把POP定义为动画引擎 我愿意称它为函数发生器)

    介绍


    官方地址 https://github.com/facebook/pop
    官方介绍(翻译版)

    POP是一个在iOS与OS X上通用的极具扩展性的动画引擎 它在基本的静态动画的基础上增加的弹簧动画与衰减动画 使之能创造出更真实更具物理性的交互动画 POP的API可以快速的与现有的ObjC代码集成并可以作用于任意对象的任意属性
    POP是个相当成熟且久经考验的框架 Facebook出品的令人惊叹的Paper应用中的所有动画和效果即出自POP

    安装方式还是推荐使用CocoaPod

    1
    pod 'pop', '~> 1.0'

    POP的神奇之处在于 它是独立与Core Animation的存在 所以 忘记Core Animation吧 忘记Layer Tree吧 迎接一个简单的明天 (LOL 开玩笑的~:) 很多地方还是会需要Core Animation的 不过说不定哪天苹果大发善心 将动画相关的部分向POP借鉴一点也不是不可能的(比如SpriteKit就借鉴了Cocos2D :)

    使用


    POP默认支持三种动画 但同时也支持自定义动画

    • POPBasicAnimation
    • POPSpringAnimation
    • POPDecayAnimation
    • POPCustomAnimation //自定义动画

    这里我们只讨论前三种(因为自定义动画我也没用过 :) 先来看看官方的示例代码吧

    官方代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //Basic animations can be used to interpolate values over a specified time period. To use an ease-in ease-out animation to animate a view's alpha from 0.0 to 1.0 over the default duration:
    POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewAlpha];
    anim.fromValue = @(0.0);
    anim.toValue = @(1.0);
    [view pop_addAnimation:anim forKey:@"fade"];

    //Spring animations can be used to give objects a delightful bounce. In this example, we use a spring animation to animate a layer's bounds from its current value to (0, 0, 400, 400):
    POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds];
    anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 400, 400)];
    [layer pop_addAnimation:anim forKey:@"size"];


    //Decay animations can be used to gradually slow an object to a halt. In this example, we decay a layer's positionX from it's current value and velocity 1000pts per second:
    POPDecayAnimation *anim = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPositionX];
    anim.velocity = @(1000.);
    [layer pop_addAnimation:anim forKey:@"slide"];

    POPBasicAnimation

    POPBasicAnimation使用最广泛 提供固定时间间隔的动画(如淡入淡出效果)

    代码示例1

    1
    2
    3
    4
    POPBasicAnimation *anBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionX];
    anBasic.toValue = @(self.square.center.y+300);
    anBasic.beginTime = CACurrentMediaTime() + 1.0f;
    [self.square pop_addAnimation:anBasic forKey:@"position"];

    其动画效果如下
    POPBasicAnimationPOPBasicAnimation

    可以看到 添加一个动画最少仅需三步

    1. 定义一个animation对象 并指定对应的动画属性
    2. 设置初始值和默认值(初始值可以不指定 会默认从当前值开始)
    3. 添加到想产生动画的对象上

    POPBasicAnimation可配置的属性与默认值为

    1
    duration:0.4    //动画间隔

    POPBasicAnimation提供四种timingfunction(很熟悉 对不对? 就是Core Animation中那些)

    • kCAMediaTimingFunctionLinear
    • kCAMediaTimingFunctionEaseIn
    • kCAMediaTimingFunctionEaseOut
    • kCAMediaTimingFunctionEaseInEaseOut

    其时间函数分别如下

    kCAMediaTimingFunctionLinearkCAMediaTimingFunctionLinear
    kCAMediaTimingFunctionEaseInkCAMediaTimingFunctionEaseIn
    kCAMediaTimingFunctionEaseOutkCAMediaTimingFunctionEaseOut
    kCAMediaTimingFunctionEaseInEaseOutkCAMediaTimingFunctionEaseInEaseOut

    POPSpringAnimation

    POPSpringAnimation也许是大多数人使用POP的理由 其提供一个类似弹簧一般的动画效果(使用后 APP立马就活泼起来了 有木有?!)

    代码示例23

    1
    2
    3
    4
    5
    POPSpringAnimation *anSpring = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionX];
    anSpring.toValue = @(self.square.center.y+300);
    anSpring.beginTime = CACurrentMediaTime() + 1.0f;
    anSpring.springBounciness = 10.0f;
    [self.square pop_addAnimation:anSpring forKey:@"position"];

    其动画效果如下
    动画效果动画效果

    POPSpringAnimation可配置的属性与默认值为

    1
    2
    3
    4
    5
    springBounciness:4.0    //[0-20] 弹力 越大则震动幅度越大
    springSpeed :12.0 //[0-20] 速度 越大则动画结束越快
    dynamicsTension :0 //拉力 接下来这三个都跟物理力学模拟相关 数值调整起来也很费时 没事不建议使用哈
    dynamicsFriction:0 //摩擦 同上
    dynamicsMass :0 //质量 同上

    注意:POPSpringAnimation是没有duration字段的 其动画持续时间由以上几个参数决定

    其时间函数如下
    时间函数时间函数

    POPDecayAnimation

    POPDecayAnimation提供一个过阻尼效果(其实Spring是一种欠阻尼效果) 可以实现类似UIScrollView的滑动衰减效果(是的 你可以靠它来自己实现一个UIScrollView)

    代码示例3

    1
    2
    3
    4
    POPDecayAnimation *anDecay = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPositionX];
    anDecay.velocity = @(600);
    anDecay.beginTime = CACurrentMediaTime() + 1.0f;
    [self.square pop_addAnimation:anDecay forKey:@"position"];

    其动画效果如下
    动画效果动画效果

    注意:这里对POPDecayAnimation设置toValue是没有意义的 会被忽略(因为目的状态是动态计算得到的)

    POPDecayAnimation可配置的属性与默认值为

    1
    deceleration:0.998  //衰减系数(越小则衰减得越快)

    注意:POPDecayAnimation也是没有duration字段的 其动画持续时间由velocity与deceleration决定

    其时间函数如下
    时间函数时间函数

    接下来我们看一下POP默认支持哪些属性的动画 打开POPAnimatablePropery.h可以看到如下定义(这些是到目前为止 所支持的属性 随着版本的更新 还在不断的新增中 :)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    /**
    Common CALayer property names.
    */
    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;

    /**
    Common CAShapeLayer property names.
    */
    extern NSString * const kPOPShapeLayerStrokeStart;
    extern NSString * const kPOPShapeLayerStrokeEnd;
    extern NSString * const kPOPShapeLayerStrokeColor;
    extern NSString * const kPOPShapeLayerFillColor;

    /**
    Common NSLayoutConstraint property names.
    */
    extern NSString * const kPOPLayoutConstraintConstant;


    #if TARGET_OS_IPHONE

    /**
    Common UIView property names.
    */
    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;

    /**
    Common UIScrollView property names.
    */
    extern NSString * const kPOPScrollViewContentOffset;
    extern NSString * const kPOPScrollViewContentSize;
    extern NSString * const kPOPScrollViewZoomScale;
    extern NSString * const kPOPScrollViewContentInset;

    /**
    Common UITableView property names.
    */
    extern NSString * const kPOPTableViewContentOffset;
    extern NSString * const kPOPTableViewContentSize;

    /**
    Common UICollectionView property names.
    */
    extern NSString * const kPOPCollectionViewContentOffset;
    extern NSString * const kPOPCollectionViewContentSize;

    /**
    Common UINavigationBar property names.
    */
    extern NSString * const kPOPNavigationBarBarTintColor;

    /**
    Common UIToolbar property names.
    */
    extern NSString * const kPOPToolbarBarTintColor;

    /**
    Common UITabBar property names.
    */
    extern NSString * const kPOPTabBarBarTintColor;

    /**
    Common UILabel property names.
    */
    extern NSString * const kPOPLabelTextColor;

    作为刚接触POP的一些同学来说 如果在上面看到你希望的某些属性的话 你可以像官方代码示例一样指定这个属性即可开始动画了
    但是如果你想要的某些属性不在之上呢 这时候自定义属性POPAnimatableProperty就排上用场了

    自定义属性

    POP默认支持的三种动画都继承自POPPropertyAnimation POPPropertyAnimation中定义了一个叫property的属性( 之前没有用到它是因为POP根据不同的默认动画属性帮你生成了默认的property) 而这个property则是用来驱动POP的动画效果中的重要一环

    代码示例4

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    POPAnimatableProperty *prop = [POPAnimatableProperty propertyWithName:@"prop" initializer:^(POPMutableAnimatableProperty *prop) {
    // read value
    prop.readBlock = ^(id obj, CGFloat values[]) {

    };
    // write value
    prop.writeBlock = ^(id obj, const CGFloat values[]) {

    };
    // dynamics threshold
    prop.threshold = 0.01;
    }];

    其组成就是一个readBlock一个writeBlock和一个threashold

    • readBlock告诉POP当前的属性值
    • writeBlock中修改变化后的属性值
    • threashold决定了动画变化间隔的阈值 值越大writeBlock的调用次数越少

    POPAnimatableProperty其实是POP中一个比较重要的东西 像上面提到的POP自带的动画属性 查看源代码可以看到也只是POP自动帮你设置好了POPAnimatableProperty而已 其作用就是当动画的某个时间片被触发时 告诉系统如何根据当前时间片做出变化

    还是以一个实际的例子来说明如何使用自定义属性 比如我们要实现一个像系统的时钟APP里秒表计时的一个效果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    POPAnimatableProperty *prop = [POPAnimatableProperty propertyWithName:@"countdown" initializer:^(POPMutableAnimatableProperty *prop) {

    prop.writeBlock = ^(id obj, const CGFloat values[]) {
    UILabel *lable = (UILabel*)obj;
    label.text = [NSString stringWithFormat:@"%02d:%02d:%02d",(int)values[0]/60,(int)values[0]%60,(int)(values[0]*100)%100];
    };

    // prop.threshold = 0.01f;
    }];

    POPBasicAnimation *anBasic = [POPBasicAnimation linearAnimation]; //秒表当然必须是线性的时间函数
    anBasic.property = prop; //自定义属性
    anBasic.fromValue = @(0); //从0开始
    anBasic.toValue = @(3*60); //180秒
    anBasic.duration = 3*60; //持续3分钟
    anBasic.beginTime = CACurrentMediaTime() + 1.0f; //延迟1秒开始
    [label pop_addAnimation:anBasic forKey:@"countdown"];

    其动画效果如下
    动画效果动画效果

    有没有从中得到一些启发呢? POP可以做的事情可远比Core Animation要多(注意这里我们使用了beginTime这个属性来设置动画的延迟施放) 例如音乐播放时那种淡入淡出的效果等等也可以用POP来实现

    小结


    其实只需要熟练掌握POP自带的三种动画 即可完成大部分的动画效果 如果实在是无法满足你的需求的话 自定义动画也基本可以满足你的要求 可以说POP化繁为简的出现 极大的方便了我们这些苦逼的coder

    当然 就像我说的 POP不仅仅是一个动画引擎 相信经过我最后一个例子 大家可以得到一点启事 POP能做的事情还不少 :)

  • 相关阅读:
    CodeForces 7B
    CodeForces 4D
    离散化
    线段树入门
    洛谷 P3951 小凯的疑惑(赛瓦维斯特定理)
    Codeforces 1295D Same GCDs (欧拉函数)
    Codeforces 1295C Obtain The String (二分)
    Codeforces 1295B Infinite Prefixes
    Codeforces 1295A Display The Number(思维)
    Codeforces 1294F Three Paths on a Tree(树的直径,思维)
  • 原文地址:https://www.cnblogs.com/itlover2013/p/5071835.html
Copyright © 2020-2023  润新知