Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ebe3de3 authored by Chet Haase's avatar Chet Haase
Browse files

Fix transitions on disappearing view hiearchies

Previously, Fade transitions did not work correctly on hirearchies; they
only handled individual views. in particular, they would side-effect all
fading views by removing them from their parent to fade them out in the
overlay of the scene root. This worked for the fade-out transition itself,
but caused problems when those same hierarchies were added back in and
another Fade was run on the hierarchy, because now all of the views inside
that parent node had been removed, so they didn't fade in at all.

The fix was to add logic in Visibility to detect when a disappearing
view was inside a hierarchy that was also disappearing, and to skip the
fade on the views inside that hierarchy, leaving only the top-most
disappearing view to be faded out, thus preserving the hierarchy under
that faded-out group.

Along the way, there were various cleanups, fixes, and refactorings in the
transition code, and slight API modifications.

Issue #9406371 Transitions: Removing view hierarchy not working correctly
Issue #9470255 Transitions: Separate different transitions by Scene Root

Change-Id: I42e80dac6097fee740f651dcc0535f2c57c11ebb
parent cb64e3e6
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -28547,28 +28547,30 @@ package android.view.transition {
    method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
  }
  public abstract class Transition {
  public abstract class Transition implements java.lang.Cloneable {
    ctor public Transition();
    method public void addListener(android.view.transition.Transition.TransitionListener);
    method protected void cancelTransition();
    method protected abstract void captureValues(android.view.transition.TransitionValues, boolean);
    method public android.view.transition.Transition clone();
    method public long getDuration();
    method public android.animation.TimeInterpolator getInterpolator();
    method public java.util.ArrayList<android.view.transition.Transition.TransitionListener> getListeners();
    method public long getStartDelay();
    method public int[] getTargetIds();
    method public android.view.View[] getTargets();
    method protected android.view.transition.TransitionValues getTransitionValues(android.view.View, boolean);
    method protected void onTransitionCancel();
    method protected void onTransitionEnd();
    method protected void onTransitionStart();
    method protected abstract android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
    method protected boolean prePlay(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
    method public void removeListener(android.view.transition.Transition.TransitionListener);
    method public android.view.transition.Transition setDuration(long);
    method public void setInterpolator(android.animation.TimeInterpolator);
    method public void setStartDelay(long);
    method public android.view.transition.Transition setTargetIds(int...);
    method public android.view.transition.Transition setTargets(android.view.View...);
    method protected boolean setup(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
  }
  public static abstract interface Transition.TransitionListener {
@@ -28618,12 +28620,12 @@ package android.view.transition {
  public abstract class Visibility extends android.view.transition.Transition {
    ctor public Visibility();
    method protected android.animation.Animator appear(android.view.ViewGroup, android.view.View, int, android.view.View, int);
    method protected android.animation.Animator appear(android.view.ViewGroup, android.view.transition.TransitionValues, int, android.view.transition.TransitionValues, int);
    method protected void captureValues(android.view.transition.TransitionValues, boolean);
    method protected android.animation.Animator disappear(android.view.ViewGroup, android.view.View, int, android.view.View, int);
    method protected android.animation.Animator disappear(android.view.ViewGroup, android.view.transition.TransitionValues, int, android.view.transition.TransitionValues, int);
    method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
    method protected boolean preAppear(android.view.ViewGroup, android.view.View, int, android.view.View, int);
    method protected boolean preDisappear(android.view.ViewGroup, android.view.View, int, android.view.View, int);
    method protected boolean setupAppear(android.view.ViewGroup, android.view.transition.TransitionValues, int, android.view.transition.TransitionValues, int);
    method protected boolean setupDisappear(android.view.ViewGroup, android.view.transition.TransitionValues, int, android.view.transition.TransitionValues, int);
  }
}
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.transition;

/**
+2 −1
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.transition;

import android.animation.Animator;
@@ -139,7 +140,7 @@ public class Crossfade extends Transition {
    }

    @Override
    protected boolean prePlay(ViewGroup sceneRoot, TransitionValues startValues,
    protected boolean setup(ViewGroup sceneRoot, TransitionValues startValues,
            TransitionValues endValues) {
        if (startValues == null || endValues == null) {
            return false;
+38 −10
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.transition;

import android.animation.Animator;
@@ -32,6 +33,8 @@ import android.view.ViewGroup;
public class Fade extends Visibility {

    private static final String LOG_TAG = "Fade";
    private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
    private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";

    /**
     * Fading mode used in {@link #Fade(int)} to make the transition
@@ -81,8 +84,19 @@ public class Fade extends Visibility {
    }

    @Override
    protected boolean preAppear(ViewGroup sceneRoot, View startView, int startVisibility,
            View endView, int endVisibility) {
    protected void captureValues(TransitionValues values, boolean start) {
        super.captureValues(values, start);
        int[] loc = new int[2];
        values.view.getLocationOnScreen(loc);
        values.values.put(PROPNAME_SCREEN_X, loc[0]);
        values.values.put(PROPNAME_SCREEN_Y, loc[1]);
    }

    @Override
    protected boolean setupAppear(ViewGroup sceneRoot,
            TransitionValues startValues, int startVisibility,
            TransitionValues endValues, int endVisibility) {
        View endView = (endValues != null) ? endValues.view : null;
        if ((mFadingMode & IN) != IN) {
            return false;
        }
@@ -91,27 +105,32 @@ public class Fade extends Visibility {
    }

    @Override
    protected Animator appear(ViewGroup sceneRoot, View startView, int startVisibility,
            View endView, int endVisibility) {
    protected Animator appear(ViewGroup sceneRoot,
            TransitionValues startValues, int startVisibility,
            TransitionValues endValues, int endVisibility) {
        View endView = (endValues != null) ? endValues.view : null;
        if ((mFadingMode & IN) != IN) {
            return null;
        }
        // TODO: hack - retain original value from before preAppear
        // TODO: hack - retain original value from before setupAppear
        return runAnimation(endView, 0, 1, null);
        // TODO: end listener to make sure we end at 1 no matter what
    }

    @Override
    protected boolean preDisappear(ViewGroup sceneRoot, View startView, int startVisibility,
            View endView, int endVisibility) {
    protected boolean setupDisappear(ViewGroup sceneRoot,
            TransitionValues startValues, int startVisibility,
            TransitionValues endValues, int endVisibility) {
        if ((mFadingMode & OUT) != OUT) {
            return false;
        }
        View view;
        View startView = (startValues != null) ? startValues.view : null;
        View endView = (endValues != null) ? endValues.view : null;
        if (Transition.DBG) {
            Log.d(LOG_TAG, "Fade.predisappear: startView, startVis, endView, endVis = " +
                        startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
        }
        View view;
        View overlayView = null;
        View viewToKeep = null;
        if (endView == null) {
@@ -137,6 +156,12 @@ public class Fade extends Visibility {
        // TODO: add automatic facility to Visibility superclass for keeping views around
        if (overlayView != null) {
            // TODO: Need to do this for general case of adding to overlay
            int screenX = (Integer) startValues.values.get(PROPNAME_SCREEN_X);
            int screenY = (Integer) startValues.values.get(PROPNAME_SCREEN_Y);
            int[] loc = new int[2];
            sceneRoot.getLocationOnScreen(loc);
            overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
            overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
            sceneRoot.getOverlay().add(overlayView);
            return true;
        }
@@ -150,11 +175,14 @@ public class Fade extends Visibility {
    }

    @Override
    protected Animator disappear(ViewGroup sceneRoot, View startView, int startVisibility,
            View endView, int endVisibility) {
    protected Animator disappear(ViewGroup sceneRoot,
            TransitionValues startValues, int startVisibility,
            TransitionValues endValues, int endVisibility) {
        if ((mFadingMode & OUT) != OUT) {
            return null;
        }
        View startView = (startValues != null) ? startValues.view : null;
        View endView = (endValues != null) ? endValues.view : null;
        if (Transition.DBG) {
            Log.d(LOG_TAG, "Fade.disappear: startView, startVis, endView, endVis = " +
                startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
+2 −1
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.transition;

import android.animation.Animator;
@@ -212,7 +213,7 @@ public class Move extends Transition {
    }

    @Override
    protected boolean prePlay(final ViewGroup sceneRoot, TransitionValues startValues,
    protected boolean setup(final ViewGroup sceneRoot, TransitionValues startValues,
            TransitionValues endValues) {
        if (startValues == null || endValues == null) {
            return false;
Loading