美文网首页
Animation组合动画踩坑-实现循环播放动画,可控制次数

Animation组合动画踩坑-实现循环播放动画,可控制次数

作者: tinyvampirepudg | 来源:发表于2021-07-17 22:41 被阅读0次

先上效果图:

在这里插入图片描述

Animation组合动画踩坑-实现循环播放动画,可控制次数

比如说期望如下:

在这里插入图片描述

如果使用View动画,那么很自然的就想到了通过res/anim下的xml文件来实现,组合动画的话使用set标签即可。

直接这样做真的能生效么?且让我们一步一步实践。先提前剧透下,官网的demo也是有问题的。

赶时间只想看解决方式的同学,可以直接移步到最后一步的demo。

1、使用res/anim下的xml文件,实现组合动画顺序执行的坑。

动画的顺序执行是依靠的startOffset属性,它的值等于前面所有动画的duration之和。我们的最直观的实现代码如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">

    <scale
        android:duration="200"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="@integer/breath_anim_repeat_count"
        android:toXScale="0.9"
        android:toYScale="0.9" />

    <scale
        android:duration="400"
        android:fromXScale="0.9"
        android:fromYScale="0.9"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="@integer/breath_anim_repeat_count"
        android:startOffset="200"
        android:toXScale="1.1"
        android:toYScale="1.1" />

    <scale
        android:duration="400"
        android:fromXScale="1.1"
        android:fromYScale="1.1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="@integer/breath_anim_repeat_count"
        android:startOffset="600"
        android:toXScale="0.9"
        android:toYScale="0.9" />

    <scale
        android:duration="200"
        android:fromXScale="0.9"
        android:fromYScale="0.9"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="@integer/breath_anim_repeat_count"
        android:startOffset="1000"
        android:toXScale="1.0"
        android:toYScale="1.0" />

</set>

但是这段动画实际执行起来是有问题的,第二段scale代码的fromXScalefromYScale会在set动画一开始就同时作用于View上,而不是按照我们的期望,在startOffset时间到了之后再生效。

虽然startOffset属性会延时动画的执行,但是fromXScalefromYScale的值不会延时生效,会从动画开始就影响set系列动画的初始状态。

官网demo也有同样的问题:https://developer.android.com/guide/topics/graphics/view-animation?hl=zh-cn#java

解决方式:

将后续动画的fromXScale和fromYScale修改为1.0,不然会影响动画的初始状态。
然后动态转换下对应动画的toXScale和toYScale的比例。

转换的结果如下表:

顺序 duration fromXScale toXScale fromYScale toYScale 转换后的fromXScale 转换后的toXScale 转换后的fromYScale 转换后的toYScale
1 200 1.0 0.9 1.0 0.9 1.0 1.0 0.9 0.9
2 400 0.9 1.1 0.9 1.1 1.0 1.0 1.2222222222222223 1.2222222222222223
3 400 1.1 0.9 1.1 0.9 1.0 1.0 0.8181818181818181 0.8181818181818181
4 200 0.9 1.0 0.9 1.0 1.0 1.0 1.1111111111111112 1.1111111111111112

2、重复次数-repeatCount的坑:

①给set设置repeatCount无效。
②给set中的各个元素设置repeatCount的话,各个动画独立执行自己的repeatCount,不会按照我们的期望,等到动画顺序执行完第一遍以后,再执行下一遍动画;而是每个scale元素立即执行自身的下一次动画,这样动画看起来就会很卡顿,不符合预期

解决方式:
将每个单独元素scale的repeatCount设置为0,具体的repeatCount逻辑依赖代码动态实现

3、取消、停止动画的坑。

取消动画的方式有三种:Animation#cancel()View#clearAnimation()View#setAnimation(null),它们各有优缺点。
Animation#cancel()会触发Animation.AnimationListener#onAnimationEnd回调,不适合在Animation.AnimationListener#onAnimationEnd回调中调用。
View#clearAnimation()也会触发Animation.AnimationListener#onAnimationEnd回调,同样不适合在Animation.AnimationListener#onAnimationEnd回调中调用。
View#setAnimation(null)不会触发Animation.AnimationListener#onAnimationEnd回调,但是它可能会导致下次调用Animation#start失败。

4、Animation.AnimationListener监听动画结束的回调不靠谱。

Animation.AnimationListener#onAnimationEnd方法不靠谱,主要是调用时机不符合预期。

参考:https://stackoverflow.com/questions/5474923/onanimationend-is-not-getting-called-onanimationstart-works-fine

Animation#cancel()View#clearAnimation()都会触发Animation.AnimationListener#onAnimationEnd回调,并且在Animation.AnimationListener#onAnimationEnd方法中,Animation#hasEnded()方法返回的是false,跟期望的true不一致。

②在Animation.AnimationListener#onAnimationEnd中调用Animation#start方法开启下一次动画时,会立即调用Animation.AnimationListener#onAnimationStartAnimation.AnimationListener#onAnimationEnd回调,中间间隔只有1ms,这就会导致少执行一次动画,跟期望不符。

解决方式:
不建议使用Animation.AnimationListener来监听动画结束,建议使用Handler#postDelay方法 + View#clearAnimation方法来实现RepeatCount功能。

最终解决方式:
①res/anim中的xml文件中的set动画,顺序执行时除了使用startOffset保证执行顺序,还需要对fromXScalefromYScaletoXScaletoYScale进行相应的转换,保证fromXScalefromYScale始终为1.0
②使用Handler#postDelay方法来实现repeatCount功能。
③使用View#clearAnimation方法来清除动画。
④再次启动动画时,先使用Animation#reset()方法重置状态,再使用Animation#start()方法启动动画。

最终解决方式:自定义BreathAnimHelper。

具体实现参考BreathAnimHelper

相关文章

  • Animation组合动画踩坑-实现循环播放动画,可控制次数

    先上效果图: Animation组合动画踩坑-实现循环播放动画,可控制次数 比如说期望如下: 如果使用View动画...

  • Android动画

    Drawable Animation 帧动画,多张图片循环播放,实现动画效果。 以Xml定义一组帧动画 onesh...

  • CSS动画

    animation动画 动画名称、时间、曲线、延迟、播放次数、结束后是否返回、动画前后的状态 infinite不限...

  • CSS动画

    animation动画 动画名称、时间、曲线、延迟、播放次数、结束后是否返回、动画前后的状态infinite不限制...

  • 无标题文章

    css3中变形与动画(下) 1.设置动画播放次数: animation-iteration-count 定义动画的...

  • 动画(css3)animation

    animation:动画名称 动画时间 运动曲线 何时开始 播放次数 是否反方向; 关于几个值,除了名字,动画时间...

  • 2017-06-18

    css3中变形与动画(上) 1.Animation 动画定义animation动画2.Animation动画播放 ...

  • Unity学习笔记-2D Animation

    脚本控制的动画播放有两种方式 a. 通过动画名直接播放 animator.Play("Animation name...

  • 动画:Core Animation

    UIView 可实现一般动画,如果更复杂动画,需要用core animation core animation基于...

  • Timeline 轨道详解 Animation Track

    简介: Animation Track 主要用来控制一个物体的动画播放状态的,Animation Track 上的...

网友评论

      本文标题:Animation组合动画踩坑-实现循环播放动画,可控制次数

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