Android 7.1 GUI系统-窗口管理WMS-窗口动画、应用动画的加载(六)
来源:互联网 发布:mariadb与mysql的区别 编辑:程序博客网 时间:2024/06/15 11:18
窗口动画的加载:
Activity窗口显示的过程中,除了窗口的申请,窗口大小的计算,窗口层级的设置等,还有窗口切换过程中的启动窗口的添加、销毁,窗口切换动画。
启动窗口,当一个新的Activity启动时系统可能会先显示一个启动窗口,这个启动窗口会等到Activity的主界面显示出来后消失,主要是为应用启动做一个过度。
启动窗口跟普通窗口本质上没去区别,大概列出调用流程,不过详细分析:
当需要添加启动窗口时(言外之意就是启动窗口不是必须要添加的),在startActivityLocked时,会通过showStartingWindow()@ActivityRecord.java调用到setAppStartingWindow()@WindowManagerService.java,有WMS安排窗口的创建、添加过程,相关的消息是ADD_STARTING,会调用到addStartingWindow()@PhoneWindowManager.java。
当启动窗口需要移除时,会发送消息REMOVE_STARTING给WMS,进一步调用removeStartingWindow()@PhoneWindowManager.java,处理销毁窗口相关的数据。
窗口的切换动画,总的就两类进入动画,退出动画。动画的属性有平移、旋转、缩放、透明度,这些属性可以组合使用,除了透明度是通过变换float值之外,其他三类属性都是用Matrix运算来实现的。
android中动画类型有好几种,如AppWindowAnimator,WindowAnimator,WindowStateAnimator,ScreenRotationAnimation,原理都是一样的。接下来主要关注动画资源是怎么加载的,动画是怎么执行的。
动画资源的加载。
1)跟窗口有关的动画WindowStateAnimator,当一个Activity启动时,会调用到WMS的relayoutWindow来申请窗口,这其中就应用到窗口的切换动画,如果窗口进入动画,具体就是调用WindowStateAnimator.java中的函数applyEnterAnimationLocked。
WindowStateAnimator除了处理surface相关的操作,还处理动画流程的跟踪。
void applyEnterAnimationLocked() @WindowStateAnimator.java{final int transit;if (mEnterAnimationPending) {mEnterAnimationPending = false;transit = WindowManagerPolicy.TRANSIT_ENTER;}else{transit = WindowManagerPolicy.TRANSIT_SHOW;}applyAnimationLocked(transit, true);}
从上面的函数中,进入动画分为TRANSIT_ENTER和TRANSIT_SHOW两种,当mEnterAnimationPending为true时,程序执行TRANSIT_ENTER动画。mEnterAnimationPending的值是在WMS中设置的,一种情况是新添加窗口addWindow时:winAnimator.mEnterAnimationPending= true;还有一种情况是relayoutVisibleWindow时,可见状态从GONE到VISIBLE:
if (oldVisibility ==View.GONE)winAnimator.mEnterAnimationPending = true;
与window相关的动画类型除了TRANSIT_ENTER和TRANSIT_SHOW外,还有:
WindowManagerPolicy.java /** Window has been added to the screen. */ public static final int TRANSIT_ENTER = 1; /** Window has been removed from the screen. */ public static final int TRANSIT_EXIT = 2; /** Window has been made visible. */ public static final int TRANSIT_SHOW = 3; /** Window has been made invisible. * TODO: Consider removal as this is unused. */ public static final int TRANSIT_HIDE = 4; /** The "application starting" preview window is no longer needed, and will * animate away to show the real window. */ public static final int TRANSIT_PREVIEW_DONE = 5;
接着看applyAnimationLocked函数在处理TRANSIT_ENTER和TRANSIT_SHOW上的区别:
boolean applyAnimationLocked(int transit, boolean isEntrance) @WindowStateAnimator.java{//如果当前正在执行动画跟这个进入动画是同类型的,那么系统不重复执行动画。if ((mLocalAnimating && mAnimationIsEntrance == isEntrance)|| mKeyguardGoingAwayAnimation) {if (mAnimation != null && mKeyguardGoingAwayAnimation&& transit == WindowManagerPolicy.TRANSIT_PREVIEW_DONE) {//如果tranit是 TRANSIT_PREVIEW_DONE,应用窗口已经绘制过了,那么动画类型将是app_starting_exit。applyFadeoutDuringKeyguardExitAnimation();}return true;}//当前屏幕处于可显示状态。if (mService.okToDisplay()) {//特殊窗口如状态栏、导航栏通过phoneWindowManager.java选择匹配的动画资源,这个函数直接返回的是动画资源的ID如:R.anim.dock_top_enter。int anim = mPolicy.selectAnimationLw(mWin, transit);int attr = -1;Animation a = null;if (anim != 0) {//加载指定动画资源ID的动画资源。a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;}else{//根据transit类型,获取相应的属性ID,如: com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation即是 TRANSIT_ENTER对应的属性id。switch (transit) {case WindowManagerPolicy.TRANSIT_ENTER:attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;break; case WindowManagerPolicy.TRANSIT_EXIT: attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation; break; case WindowManagerPolicy.TRANSIT_SHOW: attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation; break;}//加载动画资源,先有属性值attr,获取对应的动画id,然后加载指定的资源。 a = mService.mAppTransition.loadAnimationAttr(mWin.mAttrs, attr);}//设置动画,把这个动画资源a记录到WindowStateAnimator.java中的变量mAnimation中。setAnimation(a);}else{//如果当前屏幕不可见,清除动画。clearAnimation();}}
/这个函数可以根据属性id,动态获取动画资源id,这意味着可以通过这些属性自定义动画资源。
Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) @AppTransition.java{ int anim = 0; Context context = mContext; if (animAttr >= 0) { AttributeCache.Entry ent = getCachedAnimations(lp); if (ent != null) { context = ent.context;//获取动画id。 anim = ent.array.getResourceId(animAttr, 0); } } if (anim != 0) {//加载动画资源。 return AnimationUtils.loadAnimation(context, anim); } return null; }
基于Activity的应用程序可以在自定义的theme中,对动画属性进行自定义,如:
./frameworks/base/packages/SystemUI/res/values/styles.xml<style name="Animation.RecentPanel">//这里使用的是系统预安装的资源,也可以自己定义。<item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item> <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item></style>
系统预安装的动画资源在./frameworks/base/core/res/res/anim/中,这些动画通常是xml描述的,
activity_open_enter.xml<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top"> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:interpolator="@interpolator/decelerate_quart" android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true" android:duration="200"/> <translate android:fromYDelta="8%" android:toYDelta="0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" android:interpolator="@interpolator/decelerate_quint" android:duration="350"/></set>
2)跟apptransition有关的动画AppWindowAnimator。
当startactivity启动一个新的Activity,或者finishActivityLocked时,会调用WMS的prepareAppTransition,同时传入transit类型,如:TRANSIT_ACTIVITY_OPEN,TRANSIT_ACTIVITY_CLOSE等。
相关的动画类型还有:
AppTransition.java /** Not set up for a transition. */ public static final int TRANSIT_UNSET = -1; /** No animation for transition. */ public static final int TRANSIT_NONE = 0; /** A window in a new activity is being opened on top of an existing one in the same task. */ public static final int TRANSIT_ACTIVITY_OPEN = 6; /** The window in the top-most activity is being closed to reveal the * previous activity in the same task. */ public static final int TRANSIT_ACTIVITY_CLOSE = 7; /** A window in a new task is being opened on top of an existing one * in another activity's task. */ public static final int TRANSIT_TASK_OPEN = 8; /** A window in the top-most activity is being closed to reveal the * previous activity in a different task. */ public static final int TRANSIT_TASK_CLOSE = 9; /** A window in an existing task is being displayed on top of an existing one * in another activity's task. */ public static final int TRANSIT_TASK_TO_FRONT = 10; /** A window in an existing task is being put below all other tasks. */ public static final int TRANSIT_TASK_TO_BACK = 11; /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that * does, effectively closing the wallpaper. */ public static final int TRANSIT_WALLPAPER_CLOSE = 12; /** A window in a new activity that does have a wallpaper is being opened on one that didn't, * effectively opening the wallpaper. */ public static final int TRANSIT_WALLPAPER_OPEN = 13; /** A window in a new activity is being opened on top of an existing one, and both are on top * of the wallpaper. */ public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14; /** The window in the top-most activity is being closed to reveal the previous activity, and * both are on top of the wallpaper. */ public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15; /** A window in a new task is being opened behind an existing one in another activity's task. * The new window will show briefly and then be gone. */ public static final int TRANSIT_TASK_OPEN_BEHIND = 16; /** A window in a task is being animated in-place. */ public static final int TRANSIT_TASK_IN_PLACE = 17; /** An activity is being relaunched (e.g. due to configuration change). */ public static final int TRANSIT_ACTIVITY_RELAUNCH = 18; /** A task is being docked from recents. */ public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;
prepareAppTransition进一步会调用applyAnimationLocked函数。
private boolean applyAnimationLocked(AppWindowToken atoken, WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)@WindowManagerService.java {if (okToDisplay()) {//加载动画资源,Animation a = mAppTransition.loadAnimation(lp, transit, enter, mCurConfiguration.uiMode, mCurConfiguration.orientation, frame, displayFrame, insets, surfaceInsets, isVoiceInteraction, freeform, atoken.mTask.mTaskId);//设置动画。atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight, mAppTransition.canSkipFirstFrame(), mAppTransition.getAppStackClipMode());}else{atoken.mAppAnimator.clearAnimation();}}
这个loadAnimation函数跟前面WindowStateAnimator加载动画资源调用的loadAnimation(AnimationUtils.java
)函数,同名不同参数。
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int uiMode, int orientation, Rect frame, Rect displayFrame, Rect insets, @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform, int taskId)@AppTransition.java {Animation a;//Activity是与语音交互相关的。if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN || transit == TRANSIT_TASK_OPEN || transit == TRANSIT_TASK_TO_FRONT)) {//由动画属性id,然后获取到动画id。a = loadAnimationRes(lp, enter ? com.android.internal.R.anim.voice_activity_open_enter : com.android.internal.R.anim.voice_activity_open_exit);}else if(mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {//mNextAppTransitionType是对应了当前app transition所属的定制类型。a = loadAnimationRes(mNextAppTransitionPackage, enter ? mNextAppTransitionEnter : mNextAppTransitionExit);}else{int animAttr = 0;switch (transit) {//应用程序可以通过android:activityOpenEnterAnimation,android:activityCloseEnterAnimation定制动画实现。case TRANSIT_ACTIVITY_OPEN:animAttr = enter ? WindowAnimation_activityOpenEnterAnimation : WindowAnimation_activityOpenExitAnimation; break;case TRANSIT_ACTIVITY_CLOSE: animAttr = enter ? WindowAnimation_activityCloseEnterAnimation : WindowAnimation_activityCloseExitAnimation; break;}//加载动画资源。a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;} return a;}
具体看下mNextAppTransitionType== NEXT_TRANSIT_TYPE_CUSTOM相关的动画定制,相应的资源id是mNextAppTransitionEnter或mNextAppTransitionExit,是怎么设置的?
在定义一个Activity时,可以重载一个方法overridePendingTransition(intenterAnim, int exitAnim),
两个参数一个是进入动画,一个退出动画。
public void overridePendingTransition(int enterAnim, int exitAnim)@Activity.java {//调用AMS中的方法 overridePendingTransition。ActivityManagerNative.getDefault().overridePendingTransition( mToken, getPackageName(), enterAnim, exitAnim);}
public void overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim) @ActivityManagerService.java{if (self.state == ActivityState.RESUMED || self.state == ActivityState.PAUSING) {//通过WMS调用AppTransition.java中的overridePendingAppTransition。 mWindowManager.overridePendingAppTransition(packageName, enterAnim, exitAnim, null); }}
函数中的变量mNextAppTransitionEnter,mNextAppTransitionExit即是loadAnimation中用到的资源id。
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, IRemoteCallback startedCallback) @AppTransition.java{ if (isTransitionSet()) { clear(); mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM; mNextAppTransitionPackage = packageName; mNextAppTransitionEnter = enterAnim; mNextAppTransitionExit = exitAnim; postAnimationCallback(); mNextAppTransitionCallback = startedCallback; } else { postAnimationCallback(); } }
最后加载的动画资源通过atoken.mAppAnimator.setAnimation(),(其中atoken类型是AppWindowToken)存储到AppWindowAnimator.java中的变量animation中。
3)前面只是动画资源的加载过程,下面看下动画是怎么执行起来的?
- Android 7.1 GUI系统-窗口管理WMS-窗口动画、应用动画的加载(六)
- Android 7.1 GUI系统-窗口管理WMS-动画的执行(七)
- Android 7.1 GUI系统-窗口管理WMS-窗口属性(二)
- Android 7.1 GUI系统-窗口管理WMS-窗口添加(三)
- Android 7.1 GUI系统-窗口管理WMS-窗口大小计算(五)
- Android 7.1 GUI系统-窗口管理WMS-Surface管理(四)
- Android6.0 WMS(六) WMS动画管理
- Android6.0 WMS(十) WMS窗口动画从设置到显示框架
- Android6.0 WMS(十一) WMS窗口动画生成及播放
- Android 7.1 GUI系统-窗口管理WindowManagerService(一)
- 窗口加载时等待动画
- Android窗口管理服务WindowManagerService显示窗口动画的原理分析
- Android窗口管理服务WindowManagerService显示窗口动画的原理分析
- 动画窗口的实现
- 动画窗口的实现
- 窗口的简单动画
- Android 窗口管理:如何添加窗口到WMS
- 动画窗口
- MyBatis学习(四)--配置说明
- idea java web项目(spring项目)中集成webservice ,实现对外开放接口
- 浅谈C++中派生类对象的内存布局
- kafka无法创建topic
- 在ARX中通过COM在ACAD中添加菜单和工具条
- Android 7.1 GUI系统-窗口管理WMS-窗口动画、应用动画的加载(六)
- 卸载Eclipse中的插件
- 为VMware的虚拟机CentOS6.9拓展LVM
- Coursera deeplearning.ai 深度学习习题2-2-Optimization algorithms
- kaldi中跑thchs30
- IT行业背后的英雄—风险投资
- Eclipse中配置Tomcat
- 20171217
- 7-33 九宫格输入法(15 分)