Merge "Make fragment animations work when fragments go away"
diff --git a/api/current.xml b/api/current.xml
index e28bb58..f65226ed 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -202631,6 +202631,19 @@
<parameter name="drawingTime" type="long">
</parameter>
</method>
+<method name="endViewTransition"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
<method name="focusSearch"
return="android.view.View"
abstract="false"
@@ -203528,6 +203541,19 @@
visibility="public"
>
</method>
+<method name="startViewTransition"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
<method name="updateViewLayout"
return="void"
abstract="false"
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 54a8e4b..1e2bbcc 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -686,6 +686,13 @@
private void start(boolean playBackwards) {
mPlayingBackwards = playBackwards;
if ((mStartDelay == 0) && (Thread.currentThread() == Looper.getMainLooper().getThread())) {
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ for (AnimatorListener listener : tmpListeners) {
+ listener.onAnimationStart(this);
+ }
+ }
// This sets the initial value of the animation, prior to actually starting it running
setCurrentPlayTime(getCurrentPlayTime());
}
@@ -783,7 +790,9 @@
private void startAnimation() {
initAnimation();
sAnimations.add(this);
- if (mListeners != null) {
+ if (mStartDelay > 0 && mListeners != null) {
+ // Listeners were already notified in start() if startDelay is 0; this is
+ // just for delayed animations
ArrayList<AnimatorListener> tmpListeners =
(ArrayList<AnimatorListener>) mListeners.clone();
for (AnimatorListener listener : tmpListeners) {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 4d4f892..85a9d60 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -18,8 +18,7 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
+import android.animation.AnimatorListenerAdapter;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Handler;
@@ -363,11 +362,7 @@
Animator anim = loadAnimator(f, transit, true,
transitionStyle);
if (anim != null) {
- if (anim instanceof AnimatorSet) {
- ((AnimatorSet)anim).setTarget(f.mView);
- } else if (anim instanceof ObjectAnimator) {
- ((ObjectAnimator)anim).setTarget(f.mView);
- }
+ anim.setTarget(f.mView);
anim.start();
}
container.addView(f.mView);
@@ -447,17 +442,24 @@
+ " did not call through to super.onDestroyedView()");
}
if (f.mView != null && f.mContainer != null) {
+ Animator anim = null;
if (mCurState > Fragment.INITIALIZING) {
- Animator anim = loadAnimator(f, transit, true,
+ anim = loadAnimator(f, transit, false,
transitionStyle);
- if (anim != null) {
- if (anim instanceof AnimatorSet) {
- ((AnimatorSet)anim).setTarget(f.mView);
- } else if (anim instanceof ObjectAnimator) {
- ((ObjectAnimator)anim).setTarget(f.mView);
+ }
+ if (anim != null) {
+ final ViewGroup container = f.mContainer;
+ final View view = f.mView;
+ container.startViewTransition(view);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ container.endViewTransition(view);
}
- anim.start();
- }
+ });
+ anim.setTarget(f.mView);
+ anim.start();
+
}
f.mContainer.removeView(f.mView);
}
@@ -591,11 +593,7 @@
Animator anim = loadAnimator(fragment, transition, true,
transitionStyle);
if (anim != null) {
- if (anim instanceof AnimatorSet) {
- ((AnimatorSet)anim).setTarget(fragment.mView);
- } else if (anim instanceof ObjectAnimator) {
- ((ObjectAnimator)anim).setTarget(fragment.mView);
- }
+ anim.setTarget(fragment.mView);
anim.start();
}
fragment.mView.setVisibility(View.GONE);
@@ -615,11 +613,7 @@
Animator anim = loadAnimator(fragment, transition, true,
transitionStyle);
if (anim != null) {
- if (anim instanceof AnimatorSet) {
- ((AnimatorSet)anim).setTarget(fragment.mView);
- } else if (anim instanceof ObjectAnimator) {
- ((ObjectAnimator)anim).setTarget(fragment.mView);
- }
+ anim.setTarget(fragment.mView);
anim.start();
}
fragment.mView.setVisibility(View.VISIBLE);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c8b26ef..3db05b6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2603,6 +2603,9 @@
* @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
*/
public void setLayoutTransition(LayoutTransition transition) {
+ if (mTransition != null) {
+ mTransition.removeTransitionListener(mLayoutTransitionListener);
+ }
mTransition = transition;
if (mTransition != null) {
mTransition.addTransitionListener(mLayoutTransitionListener);
@@ -3731,6 +3734,54 @@
}
}
+ /**
+ * This method tells the ViewGroup that the given View object, which should have this
+ * ViewGroup as its parent,
+ * should be kept around (re-displayed when the ViewGroup draws its children) even if it
+ * is removed from its parent. This allows animations, such as those used by
+ * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
+ * the removal of views. A call to this method should always be accompanied by a later call
+ * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
+ * so that the View finally gets removed.
+ *
+ * @param view The View object to be kept visible even if it gets removed from its parent.
+ */
+ public void startViewTransition(View view) {
+ if (view.mParent == this) {
+ if (mTransitioningViews == null) {
+ mTransitioningViews = new ArrayList<View>();
+ }
+ mTransitioningViews.add(view);
+ }
+ }
+
+ /**
+ * This method should always be called following an earlier call to
+ * {@link #startViewTransition(View)}. The given View is finally removed from its parent
+ * and will no longer be displayed. Note that this method does not perform the functionality
+ * of removing a view from its parent; it just discontinues the display of a View that
+ * has previously been removed.
+ *
+ * @return view The View object that has been removed but is being kept around in the visible
+ * hierarchy by an earlier call to {@link #startViewTransition(View)}.
+ */
+ public void endViewTransition(View view) {
+ if (mTransitioningViews != null) {
+ mTransitioningViews.remove(view);
+ final ArrayList<View> disappearingChildren = mDisappearingChildren;
+ if (disappearingChildren != null && disappearingChildren.contains(view)) {
+ disappearingChildren.remove(view);
+ if (view.mAttachInfo != null) {
+ view.dispatchDetachedFromWindow();
+ }
+ if (view.mParent != null) {
+ view.mParent = null;
+ }
+ mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
+ }
+ }
+ }
+
private LayoutTransition.TransitionListener mLayoutTransitionListener =
new LayoutTransition.TransitionListener() {
@Override
@@ -3739,10 +3790,7 @@
// We only care about disappearing items, since we need special logic to keep
// those items visible after they've been 'removed'
if (transitionType == LayoutTransition.DISAPPEARING) {
- if (mTransitioningViews == null) {
- mTransitioningViews = new ArrayList<View>();
- }
- mTransitioningViews.add(view);
+ startViewTransition(view);
}
}
@@ -3750,18 +3798,7 @@
public void endTransition(LayoutTransition transition, ViewGroup container,
View view, int transitionType) {
if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
- mTransitioningViews.remove(view);
- final ArrayList<View> disappearingChildren = mDisappearingChildren;
- if (disappearingChildren != null && disappearingChildren.contains(view)) {
- disappearingChildren.remove(view);
- if (view.mAttachInfo != null) {
- view.dispatchDetachedFromWindow();
- }
- if (view.mParent != null) {
- view.mParent = null;
- }
- mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
- }
+ endViewTransition(view);
}
}
};