blob: 3c683d6b5330e96426285675d353ce5982791aa7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.widget;
18
19
20import android.content.Context;
21import android.content.res.TypedArray;
22import android.util.AttributeSet;
23import android.view.View;
24import android.view.ViewGroup;
25import android.view.animation.Animation;
26import 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
Mason Tangf70036b2010-06-14 17:47:24 -070034 * @attr ref android.R.styleable#ViewAnimator_animateFirstView
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 */
36public class ViewAnimator extends FrameLayout {
37
38 int mWhichChild = 0;
39 boolean mFirstTime = true;
Mason Tangf70036b2010-06-14 17:47:24 -070040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041 boolean mAnimateFirstTime = true;
42
43 Animation mInAnimation;
44 Animation mOutAnimation;
45
46 public ViewAnimator(Context context) {
47 super(context);
Jeff Sharkey1162fd72009-11-04 17:58:08 -080048 initViewAnimator(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 }
50
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 }
Mason Tangf70036b2010-06-14 17:47:24 -070064
65 boolean flag = a.getBoolean(com.android.internal.R.styleable.ViewAnimator_animateFirstView, true);
66 setAnimateFirstView(flag);
67
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 a.recycle();
69
Jeff Sharkey1162fd72009-11-04 17:58:08 -080070 initViewAnimator(context, attrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 }
72
Jeff Sharkey1162fd72009-11-04 17:58:08 -080073 /**
74 * Initialize this {@link ViewAnimator}, possibly setting
75 * {@link #setMeasureAllChildren(boolean)} based on {@link FrameLayout} flags.
76 */
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();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 }
Mason Tangf70036b2010-06-14 17:47:24 -070093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 /**
95 * Sets which child view will be displayed.
Mason Tangf70036b2010-06-14 17:47:24 -070096 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 * @param whichChild the index of the child view to display
98 */
Adam Cohen0b96a572011-02-10 15:56:16 -080099 @android.view.RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 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 }
Mason Tangf70036b2010-06-14 17:47:24 -0700115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 /**
117 * Returns the index of the currently displayed child view.
118 */
119 public int getDisplayedChild() {
120 return mWhichChild;
121 }
Mason Tangf70036b2010-06-14 17:47:24 -0700122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 /**
124 * Manually shows the next child.
125 */
Adam Cohen0b96a572011-02-10 15:56:16 -0800126 @android.view.RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 public void showNext() {
128 setDisplayedChild(mWhichChild + 1);
129 }
130
131 /**
132 * Manually shows the previous child.
133 */
Adam Cohen0b96a572011-02-10 15:56:16 -0800134 @android.view.RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 public void showPrevious() {
136 setDisplayedChild(mWhichChild - 1);
137 }
138
139 /**
Mason Tangf70036b2010-06-14 17:47:24 -0700140 * 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 */
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 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 * 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 */
175 void showOnly(int childIndex) {
Mason Tangf70036b2010-06-14 17:47:24 -0700176 final boolean animate = (!mFirstTime || mAnimateFirstTime);
177 showOnly(childIndex, animate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 }
179
180 @Override
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
191 public void removeAllViews() {
192 super.removeAllViews();
193 mWhichChild = 0;
194 mFirstTime = true;
195 }
196
197 @Override
198 public void removeView(View view) {
199 final int index = indexOfChild(view);
200 if (index >= 0) {
201 removeViewAt(index);
202 }
203 }
204
205 @Override
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
221 public void removeViewInLayout(View view) {
222 removeView(view);
223 }
224
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
332 public void setAnimateFirstView(boolean animate) {
333 mAnimateFirstTime = animate;
334 }
335
336 @Override
337 public int getBaseline() {
338 return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();
339 }
340}