很多用户为了手机用起来感觉上快,在开发者选项里把系统动画给关了,即把那3个缩放比例改成了0,系统默认一般是1x。个人建议调到0.5x就很合适了,没必要关闭,否则某些动效比较多的App体验会很差。
本文的问题就是,当开发者选项中的动画缩放比例被全部调成0后,App中部分设置了duration的属性动画就会失效,表现为直接从开头跳到了结尾,没有动画过程。
我们先分析下为什么会这样。
看ValueAnimator(/frameworks/base/core/java/android/animation/ValueAnimator.java)的部分源码:
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
| public final boolean doAnimationFrame(long frameTime) { ...... if (mLastFrameTime < 0) { if (mSeekFraction >= 0) { long seekTime = (long) (getScaledDuration() * mSeekFraction); mStartTime = frameTime - seekTime; mSeekFraction = -1; } mStartTimeCommitted = false; } mLastFrameTime = frameTime; final long currentTime = Math.max(frameTime, mStartTime); boolean finished = animateBasedOnTime(currentTime); if (finished) { endAnimation(); } return finished; } boolean animateBasedOnTime(long currentTime) { boolean done = false; if (mRunning) { final long scaledDuration = getScaledDuration(); ...... if (scaledDuration == 0) { done = true; } ...... } return done; } private long getScaledDuration() { return (long)(mDuration * sDurationScale); }
|
动画绘制是否结束取决于animateBasedOnTime方法,源码也注释到,如果duration为0,会忽略repeat count直接跳到结束状态。这里的sDurationScale也就是开发者选项中设置的动画缩放倍数。
我们只要在动画初始化后,通过反射来重置一下这个静态变量即可:
1 2 3 4 5 6 7 8 9 10 11
| private void resetAnimatorDurationScale() { try { Field field = ValueAnimator.class.getDeclaredField("sDurationScale"); field.setAccessible(true); if (field.getFloat(null) == 0) { field.setFloat(null, 1); } } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } }
|
但很显然,系统会在应用进程重启后第一次调用getWindowManagerService时重设这个值,所以必须得每次启动后都设置一次(比如在主Activity的onCreate中)。