blob: 71ff66b48fc9781b2e36cf8ba95b5af832350fac [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 }
Chet Haasebaea2442011-12-20 07:08:51 -0800188 if (index >= 0 && mWhichChild >= index) {
189 // Added item above current one, increment the index of the displayed child
190 setDisplayedChild(mWhichChild + 1);
191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 }
193
194 @Override
195 public void removeAllViews() {
196 super.removeAllViews();
197 mWhichChild = 0;
198 mFirstTime = true;
199 }
200
201 @Override
202 public void removeView(View view) {
203 final int index = indexOfChild(view);
204 if (index >= 0) {
205 removeViewAt(index);
206 }
207 }
208
209 @Override
210 public void removeViewAt(int index) {
211 super.removeViewAt(index);
212 final int childCount = getChildCount();
213 if (childCount == 0) {
214 mWhichChild = 0;
215 mFirstTime = true;
216 } else if (mWhichChild >= childCount) {
217 // Displayed is above child count, so float down to top of stack
218 setDisplayedChild(childCount - 1);
219 } else if (mWhichChild == index) {
220 // Displayed was removed, so show the new child living in its place
221 setDisplayedChild(mWhichChild);
222 }
223 }
224
225 public void removeViewInLayout(View view) {
226 removeView(view);
227 }
228
229 public void removeViews(int start, int count) {
230 super.removeViews(start, count);
231 if (getChildCount() == 0) {
232 mWhichChild = 0;
233 mFirstTime = true;
234 } else if (mWhichChild >= start && mWhichChild < start + count) {
235 // Try showing new displayed child, wrapping if needed
236 setDisplayedChild(mWhichChild);
237 }
238 }
239
240 public void removeViewsInLayout(int start, int count) {
241 removeViews(start, count);
242 }
243
244 /**
245 * Returns the View corresponding to the currently displayed child.
246 *
247 * @return The View currently displayed.
248 *
249 * @see #getDisplayedChild()
250 */
251 public View getCurrentView() {
252 return getChildAt(mWhichChild);
253 }
254
255 /**
256 * Returns the current animation used to animate a View that enters the screen.
257 *
258 * @return An Animation or null if none is set.
259 *
260 * @see #setInAnimation(android.view.animation.Animation)
261 * @see #setInAnimation(android.content.Context, int)
262 */
263 public Animation getInAnimation() {
264 return mInAnimation;
265 }
266
267 /**
268 * Specifies the animation used to animate a View that enters the screen.
269 *
270 * @param inAnimation The animation started when a View enters the screen.
271 *
272 * @see #getInAnimation()
273 * @see #setInAnimation(android.content.Context, int)
274 */
275 public void setInAnimation(Animation inAnimation) {
276 mInAnimation = inAnimation;
277 }
278
279 /**
280 * Returns the current animation used to animate a View that exits the screen.
281 *
282 * @return An Animation or null if none is set.
283 *
284 * @see #setOutAnimation(android.view.animation.Animation)
285 * @see #setOutAnimation(android.content.Context, int)
286 */
287 public Animation getOutAnimation() {
288 return mOutAnimation;
289 }
290
291 /**
292 * Specifies the animation used to animate a View that exit the screen.
293 *
294 * @param outAnimation The animation started when a View exit the screen.
295 *
296 * @see #getOutAnimation()
297 * @see #setOutAnimation(android.content.Context, int)
298 */
299 public void setOutAnimation(Animation outAnimation) {
300 mOutAnimation = outAnimation;
301 }
302
303 /**
304 * Specifies the animation used to animate a View that enters the screen.
305 *
306 * @param context The application's environment.
307 * @param resourceID The resource id of the animation.
308 *
309 * @see #getInAnimation()
310 * @see #setInAnimation(android.view.animation.Animation)
311 */
312 public void setInAnimation(Context context, int resourceID) {
313 setInAnimation(AnimationUtils.loadAnimation(context, resourceID));
314 }
315
316 /**
317 * Specifies the animation used to animate a View that exit the screen.
318 *
319 * @param context The application's environment.
320 * @param resourceID The resource id of the animation.
321 *
322 * @see #getOutAnimation()
323 * @see #setOutAnimation(android.view.animation.Animation)
324 */
325 public void setOutAnimation(Context context, int resourceID) {
326 setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));
327 }
328
329 /**
330 * Indicates whether the current View should be animated the first time
331 * the ViewAnimation is displayed.
332 *
333 * @param animate True to animate the current View the first time it is displayed,
334 * false otherwise.
335 */
336 public void setAnimateFirstView(boolean animate) {
337 mAnimateFirstTime = animate;
338 }
339
340 @Override
341 public int getBaseline() {
342 return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();
343 }
344}