diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index 198bfb0a414b4..e589e7c894a33 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -25,6 +25,7 @@ import android.os.Parcelable; import android.os.ResultReceiver; import android.transition.Transition; import android.transition.TransitionSet; +import android.transition.Visibility; import android.util.ArrayMap; import android.view.GhostView; import android.view.View; @@ -378,6 +379,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { transition.setEpicenterCallback(mEpicenterCallback); transition = setTargets(transition, includeTransitioningViews); } + noLayoutSuppressionForVisibilityTransitions(transition); return transition; } @@ -944,6 +946,24 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } } + /** + * Blocks suppressLayout from Visibility transitions. It is ok to suppress the layout, + * but we don't want to force the layout when suppressLayout becomes false. This leads + * to visual glitches. + */ + private static void noLayoutSuppressionForVisibilityTransitions(Transition transition) { + if (transition instanceof Visibility) { + final Visibility visibility = (Visibility) transition; + visibility.setSuppressLayout(false); + } else if (transition instanceof TransitionSet) { + final TransitionSet set = (TransitionSet) transition; + final int count = set.getTransitionCount(); + for (int i = 0; i < count; i++) { + noLayoutSuppressionForVisibilityTransitions(set.getTransitionAt(i)); + } + } + } + private static class FixedEpicenterCallback extends Transition.EpicenterCallback { private Rect mEpicenter; diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index 4eaab3748b1ed..6579212ccd2c9 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -84,6 +84,7 @@ public abstract class Visibility extends Transition { } private int mMode = MODE_IN | MODE_OUT; + private boolean mSuppressLayout = true; public Visibility() {} @@ -97,6 +98,15 @@ public abstract class Visibility extends Transition { } } + /** + * This tells the Visibility transition to suppress layout during the transition and release + * the suppression after the transition. + * @hide + */ + public void setSuppressLayout(boolean suppress) { + this.mSuppressLayout = suppress; + } + /** * Changes the transition to support appearing and/or disappearing Views, depending * on mode. @@ -428,7 +438,7 @@ public abstract class Visibility extends Transition { Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues); if (animator != null) { DisappearListener disappearListener = new DisappearListener(viewToKeep, - finalVisibility); + finalVisibility, mSuppressLayout); animator.addListener(disappearListener); animator.addPauseListener(disappearListener); addListener(disappearListener); @@ -483,14 +493,16 @@ public abstract class Visibility extends Transition { private final View mView; private final int mFinalVisibility; private final ViewGroup mParent; + private final boolean mSuppressLayout; private boolean mLayoutSuppressed; boolean mCanceled = false; - public DisappearListener(View view, int finalVisibility) { + public DisappearListener(View view, int finalVisibility, boolean suppressLayout) { this.mView = view; this.mFinalVisibility = finalVisibility; this.mParent = (ViewGroup) view.getParent(); + this.mSuppressLayout = suppressLayout; // Prevent a layout from including mView in its calculation. suppressLayout(true); } @@ -555,7 +567,7 @@ public abstract class Visibility extends Transition { } private void suppressLayout(boolean suppress) { - if (mLayoutSuppressed != suppress && mParent != null) { + if (mSuppressLayout && mLayoutSuppressed != suppress && mParent != null) { mLayoutSuppressed = suppress; mParent.suppressLayout(suppress); }