转载自  http://blog.csdn.net/guoqifa29/article/details/50458101

一、简介

开发者选项中提供了“窗口动画缩放”、“过渡动画缩放”、“动画程序时长缩放”三个可供调整动画时长的菜单项。单从名字上很难分辨出这三个选项作用目标是啥,我们先把系统语言调整为English,对应于“Window animation scale”、"Transition animation scale"、"Animator duration scale",从名字可以看出这三个选项是一个缩放因子,是动画时长duration的乘积因子(new_Duration = old_duration*scale),只是作用的目标各不相同。

我们知道Android系统根据动画目标可划分为Window动画、Activity动画、View动画,很明显上面那三个缩放因子就对应于此。

"Window animation scale",作用于非Activity窗口。比如,Dialog、toast、自定义浮窗、输入法等窗口都是该选项的作用目标

"Transition animation scale",作用于Activity窗口。Activity窗口是该选项作用目标

"Animator duration scale",作用于View。比如View属性动画、水波纹背景动画等

二、原理

上面了解了这三个缩放因子,下面来了解系统是何时为目标窗口的动画时长duration乘上该因子的。

1、Setting设置动画因子。WindowManagerService提供了

setAnimationScale() API供Setting使用。

Setting代码

packages

/

apps

/

Settings

/

src

/

com

/

android

/

settings

/

DevelopmentSettings.java

privatevoidwriteAnimationScaleOption(intwhich, ListPreference pref, Object newValue) {

try{

floatscale = newValue !=null? Float.parseFloat(newValue.toString()) :1;

mWindowManager.setAnimationScale(which, scale);

updateAnimationScaleValue(which, pref);

} catch(RemoteException e) {

}

}

2、

setAnimationScale()实现。

setAnimationScale()函数在

frameworks/base/services/core/java/com/android/server/wm/

WindowManagerService.java中。

@Override

publicvoidsetAnimationScale(intwhich,floatscale) {

if(!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,

"setAnimationScale()")) {

thrownewSecurityException("Requires SET_ANIMATION_SCALE permission");

}

scale = fixScale(scale);

switch(which) {

case0: mWindowAnimationScaleSetting = scale;break;

case1: mTransitionAnimationScaleSetting = scale;break;

case2: mAnimatorDurationScaleSetting = scale;break;

}

// Persist setting

mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE);

}

设置中三个选项设置的值最终分别保存到

mWindowAnimationScaleSetting、

mTransitionAnimationScaleSetting、

mAnimatorDurationScaleSetting三个变量中。函数最后会post一个

PERSIST_ANIMATION_SCALE消息出去,在该消息处理函数中会将三个值保存到Setting数据库中去。

3、dump缩放因子值。

利用“adb shell dumpsys window w -a”打印dump信息,从dump信息中可看见如下信息,这三个值对应于Setting中三个缩放因子。

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

4、Window动画时长设置

我们知道Window动画的设置是通过

frameworks\base\services\core\java\com\android\server\wm\

WindowStateAnimator.java文件的setAnimation()函数来完成的。

publicvoidsetAnimation(Animation anim,longstartTime) {

......

mAnimation.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());

......

}

很容易看出调用

Animation.

scaleCurrentDuration()函数来重置动画时长为duration*scale。

5、Activity动画时长设置

Activity切换动画的设置是通过

frameworks\base\services\core\java\com\android\server\wm\AppWindowAnimator.java文件的

setAnimation()函数来完成的。

publicvoidsetAnimation(Animation anim,intwidth,intheight,booleanskipFirstFrame) {

......

anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());

......

}

很容易看出调用Animation.scaleCurrentDuration()函数来重置动画时长为duration*scale。

6、View动画时长设置     View动画时长是通过

ValueAnimator.

sDurationScale静态变量来控制的。

publicstaticIWindowManager getWindowManagerService() {

synchronized(WindowManagerGlobal.class) {

if(sWindowManagerService ==null) {

sWindowManagerService = IWindowManager.Stub.asInterface(

ServiceManager.getService("window"));

try{

sWindowManagerService = getWindowManagerService();

ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());

} catch(RemoteException e) {

Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);

}

}

returnsWindowManagerService;

}

}

上述代码表示在进程启动后第一次调用

getWindowManagerService()时便会从WMS中获取缩放因子值,然后保存到ValueAnimator.sDurationScale中。

如果Setting中更新了View动画缩放因子,那么WMS中调用

dispatchNewAnimatorScaleLocked()函数后会回调上层应用的

onAnimatorScaleChanged()接口,通知应用View的动画时长Scale更新了。

publicstaticIWindowSession getWindowSession() {

synchronized(WindowManagerGlobal.class) {

if(sWindowSession ==null) {

try{

InputMethodManager imm = InputMethodManager.getInstance();

IWindowManager windowManager = getWindowManagerService();

sWindowSession = windowManager.openSession(

newIWindowSessionCallback.Stub() {

@Override

publicvoidonAnimatorScaleChanged(floatscale) {

ValueAnimator.setDurationScale(scale);

}

},

imm.getClient(), imm.getInputContext());

} catch(RemoteException e) {

Log.e(TAG, "Failed to open window session", e);

}

}

returnsWindowSession;

}

}

对于View动画,如果动画时长使用了

ValueAnimator.sDurationScale,那么必然受"Animator duration scale"控制。

三、总结

Setting中三个选项是一个动画时长的乘积因子,作用目标分别是Window、Activity、View。对于View来说,如果动画未使用

ValueAnimator.sDurationScale做一个乘积计算,那么动画时长自然不受Setting的影响。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐