OSDN Git Service

Add ability to automate animated transitions on View show/hide
authorChet Haase <chet@google.com>
Thu, 16 Sep 2010 18:15:56 +0000 (11:15 -0700)
committerChet Haase <chet@google.com>
Mon, 4 Oct 2010 22:11:36 +0000 (15:11 -0700)
Change-Id: Id6ff92c8fd06c3f5fb30c41b020b4de4f567154f

api/current.xml
core/java/android/animation/LayoutTransition.java
core/java/android/view/View.java
core/java/android/view/ViewGroup.java
core/java/android/widget/Adapter.java
core/java/android/widget/AdapterView.java

index 3105513..644a7b1 100644 (file)
  visibility="public"
 >
 </constructor>
-<method name="addTransitionListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.animation.LayoutTransition.TransitionListener">
-</parameter>
-</method>
-<method name="childAdd"
+<method name="addChild"
  return="void"
  abstract="false"
  native="false"
 <parameter name="child" type="android.view.View">
 </parameter>
 </method>
-<method name="childRemove"
+<method name="addTransitionListener"
  return="void"
  abstract="false"
  native="false"
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="parent" type="android.view.ViewGroup">
-</parameter>
-<parameter name="child" type="android.view.View">
+<parameter name="listener" type="android.animation.LayoutTransition.TransitionListener">
 </parameter>
 </method>
 <method name="getAnimator"
  visibility="public"
 >
 </method>
+<method name="hideChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
+<method name="removeChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
 <method name="removeTransitionListener"
  return="void"
  abstract="false"
 <parameter name="delay" type="long">
 </parameter>
 </method>
+<method name="showChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
 <field name="APPEARING"
  type="int"
  transient="false"
  type="float"
  transient="false"
  volatile="false"
- value="0.0010f"
+ value="0.001f"
  static="true"
  final="true"
  deprecated="not deprecated"
index 69ad67e..8f087d5 100644 (file)
@@ -544,6 +544,9 @@ public class LayoutTransition {
                         mChangingAppearingAnim.clone() :
                         mChangingDisappearingAnim.clone();
 
+                // Cache the animation in case we need to cancel it later
+                currentAnimations.put(child, anim);
+
                 // Set the target object for the animation
                 anim.setTarget(child);
 
@@ -553,13 +556,10 @@ public class LayoutTransition {
 
                 // Add a listener to track layout changes on this view. If we don't get a callback,
                 // then there's nothing to animate.
-                View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
+                final View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
                     public void onLayoutChange(View v, int left, int top, int right, int bottom,
                             int oldLeft, int oldTop, int oldRight, int oldBottom) {
 
-                        // Cache the animation in case we need to cancel it later
-                        currentAnimations.put(child, anim);
-
                         // Tell the animation to extract end values from the changed object
                         anim.setupEndValues();
 
@@ -577,19 +577,6 @@ public class LayoutTransition {
                         anim.setStartDelay(startDelay);
                         anim.setDuration(duration);
 
-                        // Remove the animation from the cache when it ends
-                        anim.addListener(new AnimatorListenerAdapter() {
-                            private boolean canceled = false;
-                            public void onAnimationCancel(Animator animator) {
-                                // we remove canceled animations immediately, not here
-                                canceled = true;
-                            }
-                            public void onAnimationEnd(Animator animator) {
-                                if (!canceled) {
-                                    currentAnimations.remove(child);
-                                }
-                            }
-                        });
                         if (anim instanceof ObjectAnimator) {
                             ((ObjectAnimator) anim).setCurrentPlayTime(0);
                         }
@@ -601,6 +588,22 @@ public class LayoutTransition {
                         layoutChangeListenerMap.remove(child);
                     }
                 };
+                // Remove the animation from the cache when it ends
+                anim.addListener(new AnimatorListenerAdapter() {
+                    private boolean canceled = false;
+                    public void onAnimationCancel(Animator animator) {
+                        // we remove canceled animations immediately, not here
+                        canceled = true;
+                        child.removeOnLayoutChangeListener(listener);
+                        layoutChangeListenerMap.remove(child);
+                    }
+                    public void onAnimationEnd(Animator animator) {
+                        if (!canceled) {
+                            currentAnimations.remove(child);
+                        }
+                    }
+                });
+
                 child.addOnLayoutChangeListener(listener);
                 // cache the listener for later removal
                 layoutChangeListenerMap.put(child, listener);
@@ -662,7 +665,8 @@ public class LayoutTransition {
         anim.setTarget(child);
         if (mListeners != null) {
             anim.addListener(new AnimatorListenerAdapter() {
-                public void onAnimationEnd() {
+                @Override
+                public void onAnimationEnd(Animator anim) {
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
                     }
@@ -684,7 +688,7 @@ public class LayoutTransition {
      * @param parent The ViewGroup to which the View is being added.
      * @param child The View being added to the ViewGroup.
      */
-    public void childAdd(ViewGroup parent, View child) {
+    public void addChild(ViewGroup parent, View child) {
         if (mListeners != null) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, APPEARING);
@@ -695,6 +699,19 @@ public class LayoutTransition {
     }
 
     /**
+     * This method is called by ViewGroup when a child view is about to be added to the
+     * container. This callback starts the process of a transition; we grab the starting
+     * values, listen for changes to all of the children of the container, and start appropriate
+     * animations.
+     *
+     * @param parent The ViewGroup to which the View is being added.
+     * @param child The View being added to the ViewGroup.
+     */
+    public void showChild(ViewGroup parent, View child) {
+        addChild(parent, child);
+    }
+
+    /**
      * This method is called by ViewGroup when a child view is about to be removed from the
      * container. This callback starts the process of a transition; we grab the starting
      * values, listen for changes to all of the children of the container, and start appropriate
@@ -703,7 +720,7 @@ public class LayoutTransition {
      * @param parent The ViewGroup from which the View is being removed.
      * @param child The View being removed from the ViewGroup.
      */
-    public void childRemove(ViewGroup parent, View child) {
+    public void removeChild(ViewGroup parent, View child) {
         if (mListeners != null) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, DISAPPEARING);
@@ -714,6 +731,19 @@ public class LayoutTransition {
     }
 
     /**
+     * This method is called by ViewGroup when a child view is about to be removed from the
+     * container. This callback starts the process of a transition; we grab the starting
+     * values, listen for changes to all of the children of the container, and start appropriate
+     * animations.
+     *
+     * @param parent The ViewGroup from which the View is being removed.
+     * @param child The View being removed from the ViewGroup.
+     */
+    public void hideChild(ViewGroup parent, View child) {
+        removeChild(parent, child);
+    }
+
+    /**
      * Add a listener that will be called when the bounds of the view change due to
      * layout processing.
      *
index 4c01f4f..1dfd2bf 100644 (file)
@@ -4905,6 +4905,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
         }
 
         if ((changed & VISIBILITY_MASK) != 0) {
+            if (mParent instanceof ViewGroup) {
+                ((ViewGroup)mParent).onChildVisibilityChanged(this, (flags & VISIBILITY_MASK));
+            }
             dispatchVisibilityChanged(this, (flags & VISIBILITY_MASK));
         }
 
index 8a3db38..6c57e1e 100644 (file)
@@ -323,6 +323,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
     // being animated.
     private ArrayList<View> mTransitioningViews;
 
+    // List of children changing visibility. This is used to potentially keep rendering
+    // views during a transition when they otherwise would have become gone/invisible
+    private ArrayList<View> mVisibilityChangingChildren;
+
     public ViewGroup(Context context) {
         super(context);
         initViewGroup();
@@ -758,6 +762,32 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
     }
 
     /**
+     * @hide
+     * @param child
+     * @param visibility
+     */
+    void onChildVisibilityChanged(View child, int visibility) {
+        if (mTransition != null) {
+            if (visibility == VISIBLE) {
+                mTransition.showChild(this, child);
+            } else {
+                mTransition.hideChild(this, child);
+            }
+            if (visibility != VISIBLE) {
+                // Only track this on disappearing views - appearing views are already visible
+                // and don't need special handling during drawChild()
+                if (mVisibilityChangingChildren == null) {
+                    mVisibilityChangingChildren = new ArrayList<View>();
+                }
+                mVisibilityChangingChildren.add(child);
+                if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
+                    addDisappearingView(child);
+                }
+            }
+        }
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -2598,7 +2628,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         }
 
         if (mTransition != null) {
-            mTransition.childAdd(this, child);
+            mTransition.addChild(this, child);
         }
 
         if (!checkLayoutParams(params)) {
@@ -2817,7 +2847,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
     private void removeViewInternal(int index, View view) {
 
         if (mTransition != null) {
-            mTransition.childRemove(this, view);
+            mTransition.removeChild(this, view);
         }
 
         boolean clearChildFocus = false;
@@ -2893,7 +2923,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
             final View view = children[i];
 
             if (mTransition != null) {
-                mTransition.childRemove(this, view);
+                mTransition.removeChild(this, view);
             }
 
             if (view == focused) {
@@ -2962,7 +2992,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
             final View view = children[i];
 
             if (mTransition != null) {
-                mTransition.childRemove(this, view);
+                mTransition.removeChild(this, view);
             }
 
             if (view == focused) {
@@ -3005,7 +3035,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
      */
     protected void removeDetachedView(View child, boolean animate) {
         if (mTransition != null) {
-            mTransition.childRemove(this, child);
+            mTransition.removeChild(this, child);
         }
 
         if (child == mFocused) {
@@ -4025,11 +4055,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
             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;
+                if (mVisibilityChangingChildren != null &&
+                        mVisibilityChangingChildren.contains(view)) {
+                    mVisibilityChangingChildren.remove(view);
+                } else {
+                    if (view.mAttachInfo != null) {
+                        view.dispatchDetachedFromWindow();
+                    }
+                    if (view.mParent != null) {
+                        view.mParent = null;
+                    }
                 }
                 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
             }
index f2b3e2a..9b6c5a4 100644 (file)
@@ -72,7 +72,7 @@ public interface Adapter {
     long getItemId(int position);
     
     /**
-     * Indicated whether the item ids are stable across changes to the
+     * Indicates whether the item ids are stable across changes to the
      * underlying data.
      * 
      * @return True if the same id always refers to the same object.
index ab75420..f5afb94 100644 (file)
@@ -172,7 +172,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
     int mItemCount;
 
     /**
-     * The number of items in the adapter before a data changed event occured.
+     * The number of items in the adapter before a data changed event occurred.
      */
     int mOldItemCount;
 
@@ -557,7 +557,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
     /**
      * @return The number of items owned by the Adapter associated with this
      *         AdapterView. (This is the number of data items, which may be
-     *         larger than the number of visible view.)
+     *         larger than the number of visible views.)
      */
     @ViewDebug.CapturedViewProperty
     public int getCount() {