Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.widget;
     18 
     19 
     20 import android.content.Context;
     21 import android.content.res.TypedArray;
     22 import android.util.AttributeSet;
     23 import android.view.View;
     24 import android.view.ViewGroup;
     25 import android.view.animation.Animation;
     26 import android.view.animation.AnimationUtils;
     27 
     28 /**
     29  * Base class for a {@link FrameLayout} container that will perform animations
     30  * when switching between its views.
     31  *
     32  * @attr ref android.R.styleable#ViewAnimator_inAnimation
     33  * @attr ref android.R.styleable#ViewAnimator_outAnimation
     34  */
     35 public class ViewAnimator extends FrameLayout {
     36 
     37     int mWhichChild = 0;
     38     boolean mFirstTime = true;
     39     boolean mAnimateFirstTime = true;
     40 
     41     Animation mInAnimation;
     42     Animation mOutAnimation;
     43 
     44     public ViewAnimator(Context context) {
     45         super(context);
     46         initViewAnimator(context, null);
     47     }
     48 
     49     public ViewAnimator(Context context, AttributeSet attrs) {
     50         super(context, attrs);
     51 
     52         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator);
     53         int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);
     54         if (resource > 0) {
     55             setInAnimation(context, resource);
     56         }
     57 
     58         resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0);
     59         if (resource > 0) {
     60             setOutAnimation(context, resource);
     61         }
     62         a.recycle();
     63 
     64         initViewAnimator(context, attrs);
     65     }
     66 
     67     /**
     68      * Initialize this {@link ViewAnimator}, possibly setting
     69      * {@link #setMeasureAllChildren(boolean)} based on {@link FrameLayout} flags.
     70      */
     71     private void initViewAnimator(Context context, AttributeSet attrs) {
     72         if (attrs == null) {
     73             // For compatibility, always measure children when undefined.
     74             mMeasureAllChildren = true;
     75             return;
     76         }
     77 
     78         // For compatibility, default to measure children, but allow XML
     79         // attribute to override.
     80         final TypedArray a = context.obtainStyledAttributes(attrs,
     81                 com.android.internal.R.styleable.FrameLayout);
     82         final boolean measureAllChildren = a.getBoolean(
     83                 com.android.internal.R.styleable.FrameLayout_measureAllChildren, true);
     84         setMeasureAllChildren(measureAllChildren);
     85         a.recycle();
     86     }
     87 
     88     /**
     89      * Sets which child view will be displayed.
     90      *
     91      * @param whichChild the index of the child view to display
     92      */
     93     public void setDisplayedChild(int whichChild) {
     94         mWhichChild = whichChild;
     95         if (whichChild >= getChildCount()) {
     96             mWhichChild = 0;
     97         } else if (whichChild < 0) {
     98             mWhichChild = getChildCount() - 1;
     99         }
    100         boolean hasFocus = getFocusedChild() != null;
    101         // This will clear old focus if we had it
    102         showOnly(mWhichChild);
    103         if (hasFocus) {
    104             // Try to retake focus if we had it
    105             requestFocus(FOCUS_FORWARD);
    106         }
    107     }
    108 
    109     /**
    110      * Returns the index of the currently displayed child view.
    111      */
    112     public int getDisplayedChild() {
    113         return mWhichChild;
    114     }
    115 
    116     /**
    117      * Manually shows the next child.
    118      */
    119     public void showNext() {
    120         setDisplayedChild(mWhichChild + 1);
    121     }
    122 
    123     /**
    124      * Manually shows the previous child.
    125      */
    126     public void showPrevious() {
    127         setDisplayedChild(mWhichChild - 1);
    128     }
    129 
    130     /**
    131      * Shows only the specified child. The other displays Views exit the screen
    132      * with the {@link #getOutAnimation() out animation} and the specified child
    133      * enters the screen with the {@link #getInAnimation() in animation}.
    134      *
    135      * @param childIndex The index of the child to be shown.
    136      */
    137     void showOnly(int childIndex) {
    138         final int count = getChildCount();
    139         for (int i = 0; i < count; i++) {
    140             final View child = getChildAt(i);
    141             final boolean checkForFirst = (!mFirstTime || mAnimateFirstTime);
    142             if (i == childIndex) {
    143                 if (checkForFirst && mInAnimation != null) {
    144                     child.startAnimation(mInAnimation);
    145                 }
    146                 child.setVisibility(View.VISIBLE);
    147                 mFirstTime = false;
    148             } else {
    149                 if (checkForFirst && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
    150                     child.startAnimation(mOutAnimation);
    151                 } else if (child.getAnimation() == mInAnimation)
    152                     child.clearAnimation();
    153                 child.setVisibility(View.GONE);
    154             }
    155         }
    156     }
    157 
    158     @Override
    159     public void addView(View child, int index, ViewGroup.LayoutParams params) {
    160         super.addView(child, index, params);
    161         if (getChildCount() == 1) {
    162             child.setVisibility(View.VISIBLE);
    163         } else {
    164             child.setVisibility(View.GONE);
    165         }
    166     }
    167 
    168     @Override
    169     public void removeAllViews() {
    170         super.removeAllViews();
    171         mWhichChild = 0;
    172         mFirstTime = true;
    173     }
    174 
    175     @Override
    176     public void removeView(View view) {
    177         final int index = indexOfChild(view);
    178         if (index >= 0) {
    179             removeViewAt(index);
    180         }
    181     }
    182 
    183     @Override
    184     public void removeViewAt(int index) {
    185         super.removeViewAt(index);
    186         final int childCount = getChildCount();
    187         if (childCount == 0) {
    188             mWhichChild = 0;
    189             mFirstTime = true;
    190         } else if (mWhichChild >= childCount) {
    191             // Displayed is above child count, so float down to top of stack
    192             setDisplayedChild(childCount - 1);
    193         } else if (mWhichChild == index) {
    194             // Displayed was removed, so show the new child living in its place
    195             setDisplayedChild(mWhichChild);
    196         }
    197     }
    198 
    199     public void removeViewInLayout(View view) {
    200         removeView(view);
    201     }
    202 
    203     public void removeViews(int start, int count) {
    204         super.removeViews(start, count);
    205         if (getChildCount() == 0) {
    206             mWhichChild = 0;
    207             mFirstTime = true;
    208         } else if (mWhichChild >= start && mWhichChild < start + count) {
    209             // Try showing new displayed child, wrapping if needed
    210             setDisplayedChild(mWhichChild);
    211         }
    212     }
    213 
    214     public void removeViewsInLayout(int start, int count) {
    215         removeViews(start, count);
    216     }
    217 
    218     /**
    219      * Returns the View corresponding to the currently displayed child.
    220      *
    221      * @return The View currently displayed.
    222      *
    223      * @see #getDisplayedChild()
    224      */
    225     public View getCurrentView() {
    226         return getChildAt(mWhichChild);
    227     }
    228 
    229     /**
    230      * Returns the current animation used to animate a View that enters the screen.
    231      *
    232      * @return An Animation or null if none is set.
    233      *
    234      * @see #setInAnimation(android.view.animation.Animation)
    235      * @see #setInAnimation(android.content.Context, int)
    236      */
    237     public Animation getInAnimation() {
    238         return mInAnimation;
    239     }
    240 
    241     /**
    242      * Specifies the animation used to animate a View that enters the screen.
    243      *
    244      * @param inAnimation The animation started when a View enters the screen.
    245      *
    246      * @see #getInAnimation()
    247      * @see #setInAnimation(android.content.Context, int)
    248      */
    249     public void setInAnimation(Animation inAnimation) {
    250         mInAnimation = inAnimation;
    251     }
    252 
    253     /**
    254      * Returns the current animation used to animate a View that exits the screen.
    255      *
    256      * @return An Animation or null if none is set.
    257      *
    258      * @see #setOutAnimation(android.view.animation.Animation)
    259      * @see #setOutAnimation(android.content.Context, int)
    260      */
    261     public Animation getOutAnimation() {
    262         return mOutAnimation;
    263     }
    264 
    265     /**
    266      * Specifies the animation used to animate a View that exit the screen.
    267      *
    268      * @param outAnimation The animation started when a View exit the screen.
    269      *
    270      * @see #getOutAnimation()
    271      * @see #setOutAnimation(android.content.Context, int)
    272      */
    273     public void setOutAnimation(Animation outAnimation) {
    274         mOutAnimation = outAnimation;
    275     }
    276 
    277     /**
    278      * Specifies the animation used to animate a View that enters the screen.
    279      *
    280      * @param context The application's environment.
    281      * @param resourceID The resource id of the animation.
    282      *
    283      * @see #getInAnimation()
    284      * @see #setInAnimation(android.view.animation.Animation)
    285      */
    286     public void setInAnimation(Context context, int resourceID) {
    287         setInAnimation(AnimationUtils.loadAnimation(context, resourceID));
    288     }
    289 
    290     /**
    291      * Specifies the animation used to animate a View that exit the screen.
    292      *
    293      * @param context The application's environment.
    294      * @param resourceID The resource id of the animation.
    295      *
    296      * @see #getOutAnimation()
    297      * @see #setOutAnimation(android.view.animation.Animation)
    298      */
    299     public void setOutAnimation(Context context, int resourceID) {
    300         setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));
    301     }
    302 
    303     /**
    304      * Indicates whether the current View should be animated the first time
    305      * the ViewAnimation is displayed.
    306      *
    307      * @param animate True to animate the current View the first time it is displayed,
    308      *                false otherwise.
    309      */
    310     public void setAnimateFirstView(boolean animate) {
    311         mAnimateFirstTime = animate;
    312     }
    313 
    314     @Override
    315     public int getBaseline() {
    316         return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();
    317     }
    318 }
    319