2.2.4版本中,我们添加了AnimationHelper,旨在更直观更方便的创建动画,提升开发的效率。
在开始之前,我们直接看一下前后的对比:

代码对比

[快速入门]-[设置动画]章节中,我们为了创建一个从下往上的动画,需要写这么一堆代码:

  1. @Override
  2. protected Animation onCreateShowAnimation() {
  3. //这里完成展示动画
  4. TranslateAnimation showAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
  5. 0,
  6. Animation.RELATIVE_TO_SELF,
  7. 0,
  8. Animation.RELATIVE_TO_SELF,
  9. 1f,
  10. Animation.RELATIVE_TO_SELF,
  11. 0);
  12. showAnimation.setDuration(500);
  13. return showAnimation;
  14. }

虽然这是很简单的代码,但对于不怎么使用动画的人来说,写起来还是比较繁琐,而且并不直观。
那么现在来看看使用AnimationHelper创建的方法:

    @Override
    protected Animation onCreateShowAnimation() {
        return AnimationHelper.asAnimation()
                .withTranslation(new TranslationConfig()
                        .from(Direction.BOTTOM))
                .toShow();
    }

是不是很直观,从底下上来。
如果还是不想写那么多代码,没关系,AnimationHelper的config基本都有内置的,您可以直接使用:

    @Override
    protected Animation onCreateShowAnimation() {
        return AnimationHelper.asAnimation()
                .withTranslation(TranslationConfig.FROM_BOTTOM)
                .toShow();
    }

看起来非常棒对吧~

我想你一定迫不及待想去替换掉现在蛋疼的裹脚布代码了,不过在开始之前,我希望你能看完本篇文档,这样对AnimationHelper的使用会更加的顺手,以及能发现一些我测试的时候无法测出来的问题。

基本使用

AnimationHelper是专门为简化BasePopupWindow动画编写而写的内置工具类,通过内置的方向枚举,我们可以轻而易举的控制动画的展现方向和轨迹,从而提升开发效率。

代码入口

对于BasePopupWindow来说,我们接受Animation或者Animator,因此AnimathionHelper也只提供了这两种动画的形式,他们分别是:

  • AnimationHelper.asAnimation():创建一个Animation
  • AnimationHelper.asAnimator():创建一个Animator

我们所有的使用都即将从这两个方法开始。

动画组合

动画的组合跟QuickPopupBuilder一样,我们通过各种config完成动画的组合,目前而言,我们提供了常见的几种config与对应的设置方法。

config 组合方法 描述
TranslationConfig withTranslation(TranslationConfig) 添加位移动画,参数配置于对应Config中
ScaleConfig withScale(ScaleConfig) 添加缩放动画,参数配置于对应Config中
RotationConfig withRotation(RotationConfig) 添加旋转动画,参数配置于对应Config中
AlphaConfig withAlpha(AlphaConfig) 添加透明度动画,参数配置于对应Config中
提示
如果您有扩展需要,您还可以继承BaseAnimationConfig去编写属于您的config,它一样能用到这套工具里。

举个例子,我们希望动画从底部往上滑,同时带有旋转,虽然是有点怪异的搭配,但相信会更好的展示出我们的动画组合:

        @Override
        protected Animation onCreateShowAnimation() {
            return AnimationHelper.asAnimation()
                    .withTranslation(TranslationConfig.FROM_BOTTOM)
                    .withRotation(new RotationConfig()
                                          .from(-360)
                                          .to(0))
                    .toShow();
        }

ezgif-1-d368b1caf4da.gif

创建

对于显示的动画,我们调用 toShow() 即可,对于dismiss动画,我们调用 toDismiss() 即可,同时这两个方法支持我们传入listener来监听创建动画的过程,在这个接口的回调中,我们可以对创建出来的动画进行修改等操作。

  • OnAnimationCreateListener
    • onAnimationCreated(@NonNull Animation animation):每个动画创建时的回调
    • onAnimationCreateFinish(@NonNull AnimationSet animationSet):所有动画创建完成后的回调
  • OnAnimatorCreateListener
    • onAnimatorCreated(@NonNull Animator animator):每个属性动画创建时的回调
    • onAnimatorCreateFinish(@NonNull AnimatorSet animatorSet):所有属性动画创建完成后的回调

      Direction

      为了直观的表达我们的动画,尽量做到“所见即所得”,AnimationHelper提供了一套基于“方向”的解决方案,即Direction类。
      Direction是一个枚举类,正如其名字字面意思,指的是方向,它拥有以下的值:
Direction TranslationConfig ScaleConfig
IDLE 静止方位,即xml中展示的状态
CENTER 中间
CENTER_HORIZONTAL 水平居中
CENTER_VERTICAL 垂直居中
LEFT IDLE下的左方 IDLE下的左边缘
TOP IDLE下的上方 IDLE下的上边缘
RIGHT IDLE下的右方 IDLE下的右边缘
BOTTOM IDLE下的下方 IDLE下的下边缘

这些方向枚举在使用的时候可以多个组合,如左上方到右下方:

new TranslationConfig()
        .from(Direction.LEFT, Direction.TOP)
        .to(Direction.RIGHT, Direction.BOTTOM)

不同Config下的Direction

对于内置的config,我们更推荐您使用from(Direction)/to(Direction) ,除了代码量减少外,主要是阅读起来非常直观。
从上面的表格中也许你能看到,每个方向对于TranslationConfigScaleConfig是有不一样的意思,因此在这里我们着重解释一下他们的区别

TranslationConfig

对于位移来说,我们着重点在于从哪到哪,比如从上到下,从左到右。
然而对于日常语言来说来说“从左到右”可以理解为从左边到右边,也可以理解为从左边到我现在的位置(假设现在的位置位于起始点右侧)。
对于程序来说,相同变量下拥有歧义是很难做出正确的回应,因此AnimationHelper采取的方案是第一种理解,即绝对方位,详细看下图(CENTER相关的因为大家都明白什么意思,此处不再详解)
架构.png
对于View自身来说,如果我们给config定了 from(BOTTOM)…to(TOP),那么最终View停留的位置是TOP的位置,而不是IDLE位置,因此在使用的时候,请务必留意您传入的方向参数。
错误案例:

  • 我希望从下往上弹出

          @Override
          protected Animation onCreateShowAnimation() {
              return AnimationHelper.asAnimation()
                      .withTranslation(new TranslationConfig()
                                               .from(Direction.BOTTOM)
                                               .to(Direction.TOP))
                      .toShow();
          }
    

    实际展示:
    image.gif
    正确示例:

  • 我希望从下往上弹出

        @Override
          protected Animation onCreateShowAnimation() {
              return AnimationHelper.asAnimation()
                      .withTranslation(new TranslationConfig()
                                               .from(Direction.BOTTOM))
                      .toShow();
          }
    

    如果您看着有from没有to觉得很不舒服(其实我也是),可以加上 to(Direction.IDLE) ,根据图上位置,意味从某个方向到View的原始位置:

          @Override
          protected Animation onCreateShowAnimation() {
              return AnimationHelper.asAnimation()
                      .withTranslation(new TranslationConfig()
                                               .from(Direction.BOTTOM)
                                               .to(Direction.IDLE))
                      .toShow();
          }
    

    示例
    123.gif

    ScaleConfig

    对于缩放来说,方向则侧重描述“边”,因为对于缩放来说,我们只关注它的缩放中心在哪,并没有方向一说。
    详见下图(CENTER相关的因为大家都明白什么意思,此处不再详解)
    架构 (1).png
    因此,当我们希望有个缩放,是从“左”放大到“右”,实际上是从左边放大到右边,因此只需要跟字面意思一样传入from(LEFT)…to(RIGHT)即可,同样的,对于dismiss来说,我们也希望从右到左缩小,因此我们也一样传入RIGHT -> LEFT:

          @Override
          protected Animation onCreateShowAnimation() {
              return AnimationHelper.asAnimation()
                      .withScale(new ScaleConfig()
                                         .from(Direction.LEFT)
                                         .to(Direction.RIGHT))
                      .toShow();
          }
    
          @Override
          protected Animation onCreateDismissAnimation() {
              return AnimationHelper.asAnimation()
                      .withScale(new ScaleConfig()
                                         .from(Direction.RIGHT)
                                         .to(Direction.LEFT))
                      .toDismiss();
          }
    

    示例
    222.gif

    内置Config

    在对应的Config中,我们内置了一些常见的Config,您可以直接使用它们,甚至修改他们也是没问题的,在下次重新使用的时候,他们将会被恢复到默认数值。