当前位置: 首页 > news >正文

Android 关闭Activity切换过渡动画

Android 9.0以前关闭过渡动画效果只需要把开发者模式中过渡动画缩放设为0就可以。也就是把def_window_transition_scale改为0%

frameworks/base/packages/SettingsProvider/res/values/defaults.xml+    <fraction name="def_window_transition_scale">100%</fraction>
-    <fraction name="def_window_transition_scale">0%</fraction>

9.0以后按这种方式修改后屏幕会闪一下黑屏,整个窗口会抖动一下,感觉动画没有完全关闭。

跟下流程发现还是有些不一样的地方。

    void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,boolean newTask, boolean keepCurTransition, ActivityOptions options) {TaskRecord rTask = r.getTask();final int taskId = rTask.taskId;// mLaunchTaskBehind tasks get placed at the back of the task stack.if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {// Last activity in task had been removed or ActivityManagerService is reusing task.// Insert or replace.// Might not even be in.insertTaskAtTop(rTask, r);}TaskRecord task = null;if (!newTask) {// If starting in an existing task, find where that is...boolean startIt = true;for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {task = mTaskHistory.get(taskNdx);if (task.getTopActivity() == null) {// All activities in task are finishing.continue;}if (task == rTask) {// Here it is!  Now, if this is not yet visible to the// user, then just add it without starting; it will// get started when the user navigates back to it.if (!startIt) {if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "+ task, new RuntimeException("here").fillInStackTrace());r.createWindowContainer();ActivityOptions.abort(options);return;}break;} else if (task.numFullscreen > 0) {startIt = false;}}}// Place a new activity at top of stack, so it is next to interact with the user.// If we are not placing the new activity frontmost, we do not want to deliver the// onUserLeaving callback to the actual frontmost activityfinal TaskRecord activityTask = r.getTask();if (task == activityTask && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {mStackSupervisor.mUserLeaving = false;if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,"startActivity() behind front, mUserLeaving=false");}task = activityTask;// Slot the activity into the history stack and proceedif (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,new RuntimeException("here").fillInStackTrace());// TODO: Need to investigate if it is okay for the controller to already be created by the// time we get to this point. I think it is, but need to double check.// Use test in b/34179495 to trace the call path.if (r.getWindowContainerController() == null) {r.createWindowContainer();}task.setFrontOfTask();if (!isHomeOrRecentsStack() || numActivities() > 0) {if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,"Prepare open transition: starting " + r);//app设置FLAG_ACTIVITY_NO_ANIMATION,主动禁用过渡动画if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);mStackSupervisor.mNoAnimActivities.add(r);} else {int transit = TRANSIT_ACTIVITY_OPEN;if (newTask) {if (r.mLaunchTaskBehind) {transit = TRANSIT_TASK_OPEN_BEHIND;} else {// If a new task is being launched, then mark the existing top activity as// supporting picture-in-picture while pausing only if the starting activity// would not be considered an overlay on top of the current activity// (eg. not fullscreen, or the assistant)if (canEnterPipOnTaskSwitch(focusedTopActivity,null /* toFrontTask */, r, options)) {focusedTopActivity.supportsEnterPipOnTaskSwitch = true;}transit = TRANSIT_TASK_OPEN;}}//准备过渡动画mWindowManager.prepareAppTransition(transit, keepCurTransition);mStackSupervisor.mNoAnimActivities.remove(r);}boolean doShow = true;if (newTask) {// Even though this activity is starting fresh, we still need// to reset it to make sure we apply affinities to move any// existing activities from other tasks in to it.// If the caller has requested that the target task be// reset, then do so.if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {resetTaskIfNeededLocked(r, r);doShow = topRunningNonDelayedActivityLocked(null) == r;}} else if (options != null && options.getAnimationType()== ActivityOptions.ANIM_SCENE_TRANSITION) {doShow = false;}if (r.mLaunchTaskBehind) {// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we// tell WindowManager that r is visible even though it is at the back of the stack.r.setVisibility(true);ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);} else if (SHOW_APP_STARTING_PREVIEW && doShow) {// Figure out if we are transitioning from another activity that is// "has the same starting icon" as the next one.  This allows the// window manager to keep the previous window it had previously// created, if it still had one.TaskRecord prevTask = r.getTask();ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked();if (prev != null) {// We don't want to reuse the previous starting preview if:// (1) The current activity is in a different task.if (prev.getTask() != prevTask) {prev = null;}// (2) The current activity is already displayed.else if (prev.nowVisible) {prev = null;}}r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));}} else {// If this is the first activity, don't do any fancy animations,// because there is nothing for it to animate on top of.ActivityOptions.abort(options);}}

最终通过调用next.setVisibility(true),调用到AppWindowToken中的setVisibility方法中把要切换的activity设为可见状态。

boolean setVisibility(WindowManager.LayoutParams lp,boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {boolean delayed = false;inPendingTransaction = false;// Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually// been set by the app now.mHiddenSetFromTransferredStartingWindow = false;// Allow for state changes and animation to be applied if:// * token is transitioning visibility state// * or the token was marked as hidden and is exiting before we had a chance to play the// transition animation// * or this is an opening app and windows are being replaced.boolean visibilityChanged = false;if (isHidden() == visible || (isHidden() && mIsExiting) || (visible && waitingForReplacement())) {final AccessibilityController accessibilityController = mService.mAccessibilityController;boolean changed = false;if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,"Changing app " + this + " hidden=" + isHidden() + " performLayout=" + performLayout);boolean runningAppAnimation = false;if (transit != WindowManager.TRANSIT_UNSET) {//使用动画,9.0之前该方法实现是在WindowManagerService中if (applyAnimationLocked(lp, transit, visible, isVoiceInteraction)) {delayed = runningAppAnimation = true;}final WindowState window = findMainWindow();//TODO (multidisplay): Magnification is supported only for the default display.if (window != null && accessibilityController != null&& getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) {accessibilityController.onAppWindowTransitionLocked(window, transit);}changed = true;}...

看下applyAnimationLocked,有这样一段代码

boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,boolean isVoiceInteraction) {//判断是否已禁用TransationAnimationif (mService.mDisableTransitionAnimation || !shouldAnimate(transit)) {if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {Slog.v(TAG_WM, "applyAnimation: transition animation is disabled or skipped."+ " atoken=" + this);}cancelAnimation();return false;}// Only apply an animation if the display isn't frozen. If it is frozen, there is no reason...

接着看WindowManagerService

WindowManagerService(Context context, InputManagerService inputManager,boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,WindowManagerPolicy policy) {installLock(this, INDEX_WINDOW);mContext = context;mHaveInputMethods = haveInputMethods;mAllowBootMessages = showBootMsgs;mOnlyCore = onlyCore;mLimitedAlphaCompositing = context.getResources().getBoolean(com.android.internal.R.bool.config_sf_limitedAlpha);mHasPermanentDpad = context.getResources().getBoolean(com.android.internal.R.bool.config_hasPermanentDpad);mInTouchMode = context.getResources().getBoolean(com.android.internal.R.bool.config_defaultInTouchMode);mDrawLockTimeoutMillis = context.getResources().getInteger(com.android.internal.R.integer.config_drawLockTimeoutMillis);mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(com.android.internal.R.bool.config_allowAnimationsInLowPowerMode);mMaxUiWidth = context.getResources().getInteger(com.android.internal.R.integer.config_maxUiWidth);//直接读取configmDisableTransitionAnimation = context.getResources().getBoolean(com.android.internal.R.bool.config_disableTransitionAnimation);mInputManager = inputManager; // Must be before createDisplayContentLocked.mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);mDisplaySettings = new DisplaySettings();mDisplaySettings.readSettingsLocked();

最后尝试把config_disableTransitionAnimation改为true,验证过渡动画关闭并且没有闪屏。

相关文章:

  • uniapp-商城-50-后台 商家信息
  • C++ 命令模式详解
  • .Net Mqtt协议-MQTTNet(一)简介
  • Ubuntu22.04怎么退出Emergency Mode(紧急模式)
  • 【许可证】Open Source Licenses
  • 两个数组的交集(暴力、set、哈希)
  • 【C++】红黑树
  • [RoarCTF 2019]Easy Calc1
  • 怎么免费下载fbx格式模型、和blender格式文件模型,还可以在线编辑修改
  • MySQL的Order by与Group by优化详解!
  • 算法-贪婪算法
  • 【Web前端开发】HTML基础
  • 服务器机架的功能和重要性
  • 【Java学习】枚举(匿名类详解)
  • akshare爬虫限制,pywencai频繁升级个人做量化,稳定数据源和券商的选择
  • 软考(信息系统运行管理员)
  • 介绍一下synchronized锁升级过程
  • 设计模式【cpp实现版本】
  • 不同环境下运行脚本如何解决pythonpath问题
  • 【 Redis | 实战篇 缓存 】
  • 要更加冷静地看待“东升西降”的判断
  • 巴基斯坦称对印度发起军事行动
  • 雇来的“妈妈”:为入狱雇主无偿带娃4年,没做好准备说再见
  • 国防部:正告菲方停止以任何方式冲撞中方核心利益
  • 百济首次实现季度营业利润扭亏,泽布替尼销售额近57亿元
  • 驱逐行动再加码?特朗普或向利比亚和卢旺达遣送非法移民