diff --git a/api/current.xml b/api/current.xml index e28bb5880fe76..f65226ede7233 100644 --- a/api/current.xml +++ b/api/current.xml @@ -202631,6 +202631,19 @@ + + + + + + + + extends Animator { private void start(boolean playBackwards) { mPlayingBackwards = playBackwards; if ((mStartDelay == 0) && (Thread.currentThread() == Looper.getMainLooper().getThread())) { + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) 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 @@ public class ValueAnimator extends Animator { 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 tmpListeners = (ArrayList) mListeners.clone(); for (AnimatorListener listener : tmpListeners) { diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 4d4f89204b634..85a9d6070a4ee 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -18,8 +18,7 @@ package android.app; 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 @@ final class FragmentManagerImpl implements FragmentManager { 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 @@ final class FragmentManagerImpl implements FragmentManager { + " 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 @@ final class FragmentManagerImpl implements FragmentManager { 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 @@ final class FragmentManagerImpl implements FragmentManager { 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 c8b26ef261ba9..3db05b60226de 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2603,6 +2603,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @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 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + /** + * 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(); + } + 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 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 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // 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(); - } - mTransitioningViews.add(view); + startViewTransition(view); } } @@ -3750,18 +3798,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) { if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) { - mTransitioningViews.remove(view); - final ArrayList 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); } } };