OSDN Git Service

Ensure entering and exiting views don't match in Fragment Transitions.
authorGeorge Mount <mount@google.com>
Wed, 9 Sep 2015 23:10:29 +0000 (16:10 -0700)
committerGeorge Mount <mount@google.com>
Thu, 10 Sep 2015 20:54:28 +0000 (13:54 -0700)
Bug 23693301

An enter or exit transition targeting an ID, name, or similar
would match by the given criteria. This disreguarded that the
exiting view should not match against the entering views, even
if they have the matching criteria.

This excludes the exiting and shared elements from participating in
the enter transition and the enter and shared elements from
participating in the exit transition.

Change-Id: I4007699d2546416008f7a9fcfdb87ff504316577

core/java/android/app/BackStackRecord.java

index 84cbea9..9081ef8 100644 (file)
@@ -1078,8 +1078,8 @@ final class BackStackRecord extends FragmentTransaction implements
      */
     private ArrayList<View> addTransitionTargets(final TransitionState state,
             final Transition enterTransition, final TransitionSet sharedElementTransition,
-            final Transition overallTransition, final View container,
-            final Fragment inFragment, final Fragment outFragment,
+            final Transition exitTransition, final Transition overallTransition,
+            final View container, final Fragment inFragment, final Fragment outFragment,
             final ArrayList<View> hiddenFragmentViews, final boolean isBack,
             final ArrayList<View> sharedElementTargets) {
         if (enterTransition == null && sharedElementTransition == null &&
@@ -1103,6 +1103,13 @@ final class BackStackRecord extends FragmentTransaction implements
                         if (sharedElementTransition != null) {
                             namedViews = mapSharedElementsIn(state, isBack, inFragment);
                             removeTargets(sharedElementTransition, sharedElementTargets);
+                            // keep the nonExistentView as excluded so the list doesn't get emptied
+                            sharedElementTargets.remove(state.nonExistentView);
+                            excludeViews(exitTransition, sharedElementTransition,
+                                    sharedElementTargets, false);
+                            excludeViews(enterTransition, sharedElementTransition,
+                                    sharedElementTargets, false);
+
                             setSharedElementTargets(sharedElementTransition,
                                     state.nonExistentView, namedViews, sharedElementTargets);
 
@@ -1126,6 +1133,12 @@ final class BackStackRecord extends FragmentTransaction implements
                             }
                             setSharedElementEpicenter(enterTransition, state);
                         }
+
+                        excludeViews(exitTransition, enterTransition, enteringViews, true);
+                        excludeViews(exitTransition, sharedElementTransition, sharedElementTargets,
+                                true);
+                        excludeViews(enterTransition, sharedElementTransition, sharedElementTargets,
+                                true);
                         return true;
                     }
                 });
@@ -1279,6 +1292,9 @@ final class BackStackRecord extends FragmentTransaction implements
             if (exitingViews == null || exitingViews.isEmpty()) {
                 exitTransition = null;
             }
+            excludeViews(enterTransition, exitTransition, exitingViews, true);
+            excludeViews(enterTransition, sharedElementTransition, sharedElementTargets, true);
+            excludeViews(exitTransition, sharedElementTransition, sharedElementTargets, true);
 
             // Set the epicenter of the exit transition
             if (mSharedElementTargetNames != null && namedViews != null) {
@@ -1299,7 +1315,7 @@ final class BackStackRecord extends FragmentTransaction implements
             if (transition != null) {
                 ArrayList<View> hiddenFragments = new ArrayList<View>();
                 ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition,
-                        sharedElementTransition, transition, sceneRoot, inFragment,
+                        sharedElementTransition, exitTransition, transition, sceneRoot, inFragment,
                         outFragment, hiddenFragments, isBack, sharedElementTargets);
 
                 transition.setNameOverrides(state.nameOverrides);
@@ -1379,6 +1395,16 @@ final class BackStackRecord extends FragmentTransaction implements
         return false;
     }
 
+    private static void excludeViews(Transition transition, Transition fromTransition,
+            ArrayList<View> views, boolean exclude) {
+        if (transition != null) {
+            final int viewCount = fromTransition == null ? 0 : views.size();
+            for (int i = 0; i < viewCount; i++) {
+                transition.excludeTarget(views.get(i), exclude);
+            }
+        }
+    }
+
     /**
      * After the transition has started, remove all targets that we added to the transitions
      * so that the transitions are left in a clean state.
@@ -1396,9 +1422,15 @@ final class BackStackRecord extends FragmentTransaction implements
                     sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
                     if (enterTransition != null) {
                         removeTargets(enterTransition, enteringViews);
+                        excludeViews(enterTransition, exitTransition, exitingViews, false);
+                        excludeViews(enterTransition, sharedElementTransition, sharedElementTargets,
+                                false);
                     }
                     if (exitTransition != null) {
                         removeTargets(exitTransition, exitingViews);
+                        excludeViews(exitTransition, enterTransition, enteringViews, false);
+                        excludeViews(exitTransition, sharedElementTransition, sharedElementTargets,
+                                false);
                     }
                     if (sharedElementTransition != null) {
                         removeTargets(sharedElementTransition, sharedElementTargets);