Android ValueAnimator时长错乱或者不起作用的解决方法以及问题分析
2018-01-24 17:07
555 查看
今天在低端机上面测试,发现里面的属性动画竟然无法正常播放, 一下子就从起点跳到终点。
一番调试无果后,就感觉是手机本身问题, 于是就想看看其他应用的属性动画在这台手机上是否也这样:
记得之开布局边界时,看到 网易云音乐客户端 的音乐播放界面中的光盘旋转效果是属性动画,于是打开应用后,随便播放一首歌,发现光盘果然是不转了,这时忽然想到 设置-开发者选项中有几个动画时长缩放的选项,打开一看,原来是 “动画程序时长缩放” 这个选项选择了关闭动画,重新打开后果然恢复正常了。
但是实际应用中总不能提示用户手动开启吧, 究竟设置中的这个选项是怎样影响到我们应用中的动画时长的呢。
还是先说解决方法吧:(经测试,每次在activity recreate后都会重置动画时长为系统指定的值, 哈哈,所以如果想偷懒,只在Application onCreate里面调用下面的方法的话,依然是不起作用的,建议每次播放动画前重置一下。)
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
下面说说原因:
打开ValueAnimator源码,看到一个私有的静态变量 sDurationScale:
2
3
4
5
6
7
8
难道是这个东西在作怪?看看下面的方法:
这个方法是处理动画帧的方法, 更新了mLastFrameTime后, 判断动画是否已经播放完毕,
如果播放完毕,就进行结束动画的一系列处理: 回调接口、重置状态等
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我们来看看他是怎样判断动画是否播放完毕的:
这次我们要关注的是getScaledDuration这个方法, 因为这个方法返回的值能决定是否播放完毕
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
getScaledDuration方法:
是用我们设定的动画时长 * mDurationScale, 如果mDurationScale为0, 那么就满足上面的条件,直接认为动画播放完毕了
2
3
下面我们来验证一下 设置-开发者选项-动画时长缩放 这个选项是否跟mDurationScale有关:
2
3
4
5
6
7
8
9
先是默认的:
日志输出:
再试试5x的:
日志输出:
没错了,最后试试关闭动画:
日志输出果然是0.0。 我们再播放一个ValueAnimator来测试下:
2
3
输出:
2
输出0之后,直接是100了,这就对应了开头描述的情况:一下子就从起点跳到终点。
最后我们试试在动画开始前重置mDurationScale:
2
3
4
输出:
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
正常了,哈哈
有错误的地方请指出,谢谢大家!
一番调试无果后,就感觉是手机本身问题, 于是就想看看其他应用的属性动画在这台手机上是否也这样:
记得之开布局边界时,看到 网易云音乐客户端 的音乐播放界面中的光盘旋转效果是属性动画,于是打开应用后,随便播放一首歌,发现光盘果然是不转了,这时忽然想到 设置-开发者选项中有几个动画时长缩放的选项,打开一看,原来是 “动画程序时长缩放” 这个选项选择了关闭动画,重新打开后果然恢复正常了。
但是实际应用中总不能提示用户手动开启吧, 究竟设置中的这个选项是怎样影响到我们应用中的动画时长的呢。
还是先说解决方法吧:(经测试,每次在activity recreate后都会重置动画时长为系统指定的值, 哈哈,所以如果想偷懒,只在Application onCreate里面调用下面的方法的话,依然是不起作用的,建议每次播放动画前重置一下。)
public class ValueAnimatorUtil { /** * 如果动画被禁用,则重置动画缩放时长 */ public static void resetDurationScaleIfDisable() { if (getDurationScale() == 0) resetDurationScale(); } /** * 重置动画缩放时长 */ public static void resetDurationScale() { try { getField().setFloat(null, 1); } catch (Exception e) { e.printStackTrace(); } } private static float getDurationScale() { try { return getField().getFloat(null); } catch (Exception e) { e.printStackTrace(); return -1; } } @NonNull private static Field getField() throws NoSuchFieldException { Field field = ValueAnimator.class.getDeclaredField("sDurationScale"); field.setAccessible(true); return field; } }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
下面说说原因:
打开ValueAnimator源码,看到一个私有的静态变量 sDurationScale:
public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback { private static final String TAG = "ValueAnimator"; private static final boolean DEBUG = false; /** * Internal constants */ private static float sDurationScale = 1.0f;1
2
3
4
5
6
7
8
难道是这个东西在作怪?看看下面的方法:
这个方法是处理动画帧的方法, 更新了mLastFrameTime后, 判断动画是否已经播放完毕,
如果播放完毕,就进行结束动画的一系列处理: 回调接口、重置状态等
/** * Processes a frame of the animation, adjusting the start time if needed. * * @param frameTime The frame time. * @return true if the animation has ended. * @hide */ public final boolean doAnimationFrame(long frameTime) { .... .... mLastFrameTime = frameTime; final long currentTime = Math.max(frameTime, mStartTime); boolean finished = animateBasedOnTime(currentTime); if (finished) { endAnimation(); } return finished; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我们来看看他是怎样判断动画是否播放完毕的:
这次我们要关注的是getScaledDuration这个方法, 因为这个方法返回的值能决定是否播放完毕
boolean animateBasedOnTime(long currentTime) { boolean done = false; if (mRunning) { final long scaledDuration = getScaledDuration(); final float fraction = scaledDuration > 0 ? (float)(currentTime - mStartTime) / scaledDuration : 1f; final float lastFraction = mOverallFraction; final boolean newIteration = (int) fraction > (int) lastFraction; final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) && (mRepeatCount != INFINITE); if (scaledDuration == 0) { // 0 duration animator, ignore the repeat count and skip to the end done = true; } else if (newIteration && !lastIterationFinished) { // Time to repeat if (mListeners != null) { int numListeners = mListeners.size(); for (int i = 0; i < numListeners; ++i) { mListeners.get(i).onAnimationRepeat(this); } } } else if (lastIterationFinished) { done = true; } mOverallFraction = clampFraction(fraction); float currentIterationFraction = getCurrentIterationFraction( mOverallFraction, mReversing); animateValue(currentIterationFraction); } return done; }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
getScaledDuration方法:
是用我们设定的动画时长 * mDurationScale, 如果mDurationScale为0, 那么就满足上面的条件,直接认为动画播放完毕了
private long getScaledDuration() { return (long)(mDuration * sDurationScale); }1
2
3
下面我们来验证一下 设置-开发者选项-动画时长缩放 这个选项是否跟mDurationScale有关:
try { Field field = ValueAnimator.class.getDeclaredField("sDurationScale"); field.setAccessible(true); LogUtil.print(field.getFloat(null)); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }1
2
3
4
5
6
7
8
9
先是默认的:
日志输出:
1.01
再试试5x的:
日志输出:
5.01
没错了,最后试试关闭动画:
日志输出果然是0.0。 我们再播放一个ValueAnimator来测试下:
ValueAnimator animator = ValueAnimator.ofInt(0, 100).setDuration(1000); animator.addUpdateListener(animation -> LogUtil.print(animation.getAnimatedValue())); animator.start();1
2
3
输出:
11-24 21:22:59.925 9244-9244/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 0 11-24 21:23:00.087 9244-9244/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 1001
2
输出0之后,直接是100了,这就对应了开头描述的情况:一下子就从起点跳到终点。
最后我们试试在动画开始前重置mDurationScale:
ValueAnimator animator = ValueAnimator.ofInt(0, 100).setDuration(1000); animator.addUpdateListener(animation -> LogUtil.print(animation.getAnimatedValue())); ValueAnimatorUtil.resetDurationScale(); animator.start();1
2
3
4
输出:
11-24 21:30:35.102 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 0 11-24 21:30:35.261 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 0 11-24 21:30:35.332 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 1 11-24 21:30:35.393 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 5 11-24 21:30:35.406 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 6 11-24 21:30:35.424 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 7 11-24 21:30:35.442 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 9 11-24 21:30:35.460 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 11 11-24 21:30:35.478 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 13 11-24 21:30:35.496 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 14 11-24 21:30:35.515 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 17 11-24 21:30:35.534 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 19 11-24 21:30:35.551 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 21 11-24 21:30:35.569 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 24 11-24 21:30:35.587 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 26 11-24 21:30:35.605 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 28 11-24 21:30:35.623 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 31 11-24 21:30:35.641 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 34 11-24 21:30:35.659 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 36 11-24 21:30:35.677 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 39 11-24 21:30:35.696 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 42 11-24 21:30:35.713 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 45 11-24 21:30:35.732 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 48 11-24 21:30:35.750 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 51 11-24 21:30:35.768 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 53 11-24 21:30:35.786 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 56 11-24 21:30:35.804 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 59 11-24 21:30:35.822 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 62 11-24 21:30:35.840 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 65 11-24 21:30:35.858 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 67 11-24 21:30:35.877 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 70 11-24 21:30:35.895 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 72 11-24 21:30:35.913 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 75 11-24 21:30:35.931 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 77 11-24 21:30:35.951 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 80 11-24 21:30:35.969 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 82 11-24 21:30:35.987 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 84 11-24 21:30:36.004 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 86 11-24 21:30:36.022 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 88 11-24 21:30:36.040 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 90 11-24 21:30:36.058 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 91 11-24 21:30:36.076 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 93 11-24 21:30:36.095 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 94 11-24 21:30:36.112 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 95 11-24 21:30:36.130 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 96 11-24 21:30:36.148 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 97 11-24 21:30:36.167 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 98 11-24 21:30:36.185 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 99 11-24 21:30:36.203 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 99 11-24 21:30:36.221 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 99 11-24 21:30:36.239 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 99 11-24 21:30:36.257 12224-12224/com.test E/com.test.TestActivity-->lambda$onCreate$0$TestActivity: 1001
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
正常了,哈哈
有错误的地方请指出,谢谢大家!
相关文章推荐
- Android ValueAnimator时长错乱或者不起作用的解决方法以及问题分析
- 用gradle管理android项目出现的问题以及解决方法
- android开发环境遇到adt无法启动的问题分析及解决方法
- 深入android中The connection to adb is down的问题以及解决方法
- Android类app的安全问题造成漏洞的原因以及解决方法
- CString与char[] 的相互转换方法以及结尾乱码问题的分析解决
- android可能遇到问题,以及找到的解决方法小总结!
- 【android】把view保存为图片的方法以及解决保存后图片背景变黑色的问题
- Android常见问题分析之自定义ListView FastScroller滑块图片 以及 android:fastScrollEnabled="true" 不起作用
- Mac中用Ant实现Android的批量打包碰到的一些问题以及解决方法
- CString与char[] 的相互转换方法以及结尾乱码问题的分析解决
- Android 触摸屏(TP)问题现象分析和解决方法汇总
- 配置JBox2D for android遇到的问题以及解决方法
- 【android】从源码分析调用ViewPager的notifyDataSetChanged无刷新的问题及解决方法
- Cocos2dx编译到android遇到的一个坑爹问题以及解决方法
- 在用到iframe的前端页面调用c++的或者android方法时提示找不到方法问题解决
- 关于图片资源在android2.1/2.2/2.3下无法显示的问题以及解决方法
- 编译Android源码时常见问题以及解决方法
- Android 触摸屏(TP)问题现象分析和解决方法汇总
- 关于Android发送短信字数问题的分析及解决方法