• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * @attr ref android.R.styleable#ViewAnimator_animateFirstView
35  */
36 public class ViewAnimator extends FrameLayout {
37 
38     int mWhichChild = 0;
39     boolean mFirstTime = true;
40 
41     boolean mAnimateFirstTime = true;
42 
43     Animation mInAnimation;
44     Animation mOutAnimation;
45 
ViewAnimator(Context context)46     public ViewAnimator(Context context) {
47         super(context);
48         initViewAnimator(context, null);
49     }
50 
ViewAnimator(Context context, AttributeSet attrs)51     public ViewAnimator(Context context, AttributeSet attrs) {
52         super(context, attrs);
53 
54         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator);
55         int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);
56         if (resource > 0) {
57             setInAnimation(context, resource);
58         }
59 
60         resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0);
61         if (resource > 0) {
62             setOutAnimation(context, resource);
63         }
64 
65         boolean flag = a.getBoolean(com.android.internal.R.styleable.ViewAnimator_animateFirstView, true);
66         setAnimateFirstView(flag);
67 
68         a.recycle();
69 
70         initViewAnimator(context, attrs);
71     }
72 
73     /**
74      * Initialize this {@link ViewAnimator}, possibly setting
75      * {@link #setMeasureAllChildren(boolean)} based on {@link FrameLayout} flags.
76      */
initViewAnimator(Context context, AttributeSet attrs)77     private void initViewAnimator(Context context, AttributeSet attrs) {
78         if (attrs == null) {
79             // For compatibility, always measure children when undefined.
80             mMeasureAllChildren = true;
81             return;
82         }
83 
84         // For compatibility, default to measure children, but allow XML
85         // attribute to override.
86         final TypedArray a = context.obtainStyledAttributes(attrs,
87                 com.android.internal.R.styleable.FrameLayout);
88         final boolean measureAllChildren = a.getBoolean(
89                 com.android.internal.R.styleable.FrameLayout_measureAllChildren, true);
90         setMeasureAllChildren(measureAllChildren);
91         a.recycle();
92     }
93 
94     /**
95      * Sets which child view will be displayed.
96      *
97      * @param whichChild the index of the child view to display
98      */
99     @android.view.RemotableViewMethod
setDisplayedChild(int whichChild)100     public void setDisplayedChild(int whichChild) {
101         mWhichChild = whichChild;
102         if (whichChild >= getChildCount()) {
103             mWhichChild = 0;
104         } else if (whichChild < 0) {
105             mWhichChild = getChildCount() - 1;
106         }
107         boolean hasFocus = getFocusedChild() != null;
108         // This will clear old focus if we had it
109         showOnly(mWhichChild);
110         if (hasFocus) {
111             // Try to retake focus if we had it
112             requestFocus(FOCUS_FORWARD);
113         }
114     }
115 
116     /**
117      * Returns the index of the currently displayed child view.
118      */
getDisplayedChild()119     public int getDisplayedChild() {
120         return mWhichChild;
121     }
122 
123     /**
124      * Manually shows the next child.
125      */
126     @android.view.RemotableViewMethod
showNext()127     public void showNext() {
128         setDisplayedChild(mWhichChild + 1);
129     }
130 
131     /**
132      * Manually shows the previous child.
133      */
134     @android.view.RemotableViewMethod
showPrevious()135     public void showPrevious() {
136         setDisplayedChild(mWhichChild - 1);
137     }
138 
139     /**
140      * Shows only the specified child. The other displays Views exit the screen,
141      * optionally with the with the {@link #getOutAnimation() out animation} and
142      * the specified child enters the screen, optionally with the
143      * {@link #getInAnimation() in animation}.
144      *
145      * @param childIndex The index of the child to be shown.
146      * @param animate Whether or not to use the in and out animations, defaults
147      *            to true.
148      */
showOnly(int childIndex, boolean animate)149     void showOnly(int childIndex, boolean animate) {
150         final int count = getChildCount();
151         for (int i = 0; i < count; i++) {
152             final View child = getChildAt(i);
153             if (i == childIndex) {
154                 if (animate && mInAnimation != null) {
155                     child.startAnimation(mInAnimation);
156                 }
157                 child.setVisibility(View.VISIBLE);
158                 mFirstTime = false;
159             } else {
160                 if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
161                     child.startAnimation(mOutAnimation);
162                 } else if (child.getAnimation() == mInAnimation)
163                     child.clearAnimation();
164                 child.setVisibility(View.GONE);
165             }
166         }
167     }
168     /**
169      * Shows only the specified child. The other displays Views exit the screen
170      * with the {@link #getOutAnimation() out animation} and the specified child
171      * enters the screen with the {@link #getInAnimation() in animation}.
172      *
173      * @param childIndex The index of the child to be shown.
174      */
showOnly(int childIndex)175     void showOnly(int childIndex) {
176         final boolean animate = (!mFirstTime || mAnimateFirstTime);
177         showOnly(childIndex, animate);
178     }
179 
180     @Override
addView(View child, int index, ViewGroup.LayoutParams params)181     public void addView(View child, int index, ViewGroup.LayoutParams params) {
182         super.addView(child, index, params);
183         if (getChildCount() == 1) {
184             child.setVisibility(View.VISIBLE);
185         } else {
186             child.setVisibility(View.GONE);
187         }
188     }
189 
190     @Override
removeAllViews()191     public void removeAllViews() {
192         super.removeAllViews();
193         mWhichChild = 0;
194         mFirstTime = true;
195     }
196 
197     @Override
removeView(View view)198     public void removeView(View view) {
199         final int index = indexOfChild(view);
200         if (index >= 0) {
201             removeViewAt(index);
202         }
203     }
204 
205     @Override
removeViewAt(int index)206     public void removeViewAt(int index) {
207         super.removeViewAt(index);
208         final int childCount = getChildCount();
209         if (childCount == 0) {
210             mWhichChild = 0;
211             mFirstTime = true;
212         } else if (mWhichChild >= childCount) {
213             // Displayed is above child count, so float down to top of stack
214             setDisplayedChild(childCount - 1);
215         } else if (mWhichChild == index) {
216             // Displayed was removed, so show the new child living in its place
217             setDisplayedChild(mWhichChild);
218         }
219     }
220 
removeViewInLayout(View view)221     public void removeViewInLayout(View view) {
222         removeView(view);
223     }
224 
removeViews(int start, int count)225     public void removeViews(int start, int count) {
226         super.removeViews(start, count);
227         if (getChildCount() == 0) {
228             mWhichChild = 0;
229             mFirstTime = true;
230         } else if (mWhichChild >= start && mWhichChild < start + count) {
231             // Try showing new displayed child, wrapping if needed
232             setDisplayedChild(mWhichChild);
233         }
234     }
235 
removeViewsInLayout(int start, int count)236     public void removeViewsInLayout(int start, int count) {
237         removeViews(start, count);
238     }
239 
240     /**
241      * Returns the View corresponding to the currently displayed child.
242      *
243      * @return The View currently displayed.
244      *
245      * @see #getDisplayedChild()
246      */
getCurrentView()247     public View getCurrentView() {
248         return getChildAt(mWhichChild);
249     }
250 
251     /**
252      * Returns the current animation used to animate a View that enters the screen.
253      *
254      * @return An Animation or null if none is set.
255      *
256      * @see #setInAnimation(android.view.animation.Animation)
257      * @see #setInAnimation(android.content.Context, int)
258      */
getInAnimation()259     public Animation getInAnimation() {
260         return mInAnimation;
261     }
262 
263     /**
264      * Specifies the animation used to animate a View that enters the screen.
265      *
266      * @param inAnimation The animation started when a View enters the screen.
267      *
268      * @see #getInAnimation()
269      * @see #setInAnimation(android.content.Context, int)
270      */
setInAnimation(Animation inAnimation)271     public void setInAnimation(Animation inAnimation) {
272         mInAnimation = inAnimation;
273     }
274 
275     /**
276      * Returns the current animation used to animate a View that exits the screen.
277      *
278      * @return An Animation or null if none is set.
279      *
280      * @see #setOutAnimation(android.view.animation.Animation)
281      * @see #setOutAnimation(android.content.Context, int)
282      */
getOutAnimation()283     public Animation getOutAnimation() {
284         return mOutAnimation;
285     }
286 
287     /**
288      * Specifies the animation used to animate a View that exit the screen.
289      *
290      * @param outAnimation The animation started when a View exit the screen.
291      *
292      * @see #getOutAnimation()
293      * @see #setOutAnimation(android.content.Context, int)
294      */
setOutAnimation(Animation outAnimation)295     public void setOutAnimation(Animation outAnimation) {
296         mOutAnimation = outAnimation;
297     }
298 
299     /**
300      * Specifies the animation used to animate a View that enters the screen.
301      *
302      * @param context The application's environment.
303      * @param resourceID The resource id of the animation.
304      *
305      * @see #getInAnimation()
306      * @see #setInAnimation(android.view.animation.Animation)
307      */
setInAnimation(Context context, int resourceID)308     public void setInAnimation(Context context, int resourceID) {
309         setInAnimation(AnimationUtils.loadAnimation(context, resourceID));
310     }
311 
312     /**
313      * Specifies the animation used to animate a View that exit the screen.
314      *
315      * @param context The application's environment.
316      * @param resourceID The resource id of the animation.
317      *
318      * @see #getOutAnimation()
319      * @see #setOutAnimation(android.view.animation.Animation)
320      */
setOutAnimation(Context context, int resourceID)321     public void setOutAnimation(Context context, int resourceID) {
322         setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));
323     }
324 
325     /**
326      * Indicates whether the current View should be animated the first time
327      * the ViewAnimation is displayed.
328      *
329      * @param animate True to animate the current View the first time it is displayed,
330      *                false otherwise.
331      */
setAnimateFirstView(boolean animate)332     public void setAnimateFirstView(boolean animate) {
333         mAnimateFirstTime = animate;
334     }
335 
336     @Override
getBaseline()337     public int getBaseline() {
338         return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();
339     }
340 }
341