blob: 7b668932fc9aee6cd36b24a0c80d666b5e6e17e4 [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 */
99 public void setDisplayedChild(int whichChild) {
100 mWhichChild = whichChild;
101 if (whichChild >= getChildCount()) {
102 mWhichChild = 0;
103 } else if (whichChild < 0) {
104 mWhichChild = getChildCount() - 1;
105 }
106 boolean hasFocus = getFocusedChild() != null;
107 // This will clear old focus if we had it
108 showOnly(mWhichChild);
109 if (hasFocus) {
110 // Try to retake focus if we had it
111 requestFocus(FOCUS_FORWARD);
112 }
113 }
Mason Tangf70036b2010-06-14 17:47:24 -0700114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 /**
116 * Returns the index of the currently displayed child view.
117 */
118 public int getDisplayedChild() {
119 return mWhichChild;
120 }
Mason Tangf70036b2010-06-14 17:47:24 -0700121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 /**
123 * Manually shows the next child.
124 */
125 public void showNext() {
126 setDisplayedChild(mWhichChild + 1);
127 }
128
129 /**
130 * Manually shows the previous child.
131 */
132 public void showPrevious() {
133 setDisplayedChild(mWhichChild - 1);
134 }
135
136 /**
Mason Tangf70036b2010-06-14 17:47:24 -0700137 * Shows only the specified child. The other displays Views exit the screen,
138 * optionally with the with the {@link #getOutAnimation() out animation} and
139 * the specified child enters the screen, optionally with the
140 * {@link #getInAnimation() in animation}.
141 *
142 * @param childIndex The index of the child to be shown.
143 * @param animate Whether or not to use the in and out animations, defaults
144 * to true.
145 */
146 void showOnly(int childIndex, boolean animate) {
147 final int count = getChildCount();
148 for (int i = 0; i < count; i++) {
149 final View child = getChildAt(i);
150 if (i == childIndex) {
151 if (animate && mInAnimation != null) {
152 child.startAnimation(mInAnimation);
153 }
154 child.setVisibility(View.VISIBLE);
155 mFirstTime = false;
156 } else {
157 if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
158 child.startAnimation(mOutAnimation);
159 } else if (child.getAnimation() == mInAnimation)
160 child.clearAnimation();
161 child.setVisibility(View.GONE);
162 }
163 }
164 }
165 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 * Shows only the specified child. The other displays Views exit the screen
167 * with the {@link #getOutAnimation() out animation} and the specified child
168 * enters the screen with the {@link #getInAnimation() in animation}.
169 *
170 * @param childIndex The index of the child to be shown.
171 */
172 void showOnly(int childIndex) {
Mason Tangf70036b2010-06-14 17:47:24 -0700173 final boolean animate = (!mFirstTime || mAnimateFirstTime);
174 showOnly(childIndex, animate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 }
176
177 @Override
178 public void addView(View child, int index, ViewGroup.LayoutParams params) {
179 super.addView(child, index, params);
180 if (getChildCount() == 1) {
181 child.setVisibility(View.VISIBLE);
182 } else {
183 child.setVisibility(View.GONE);
184 }
185 }
186
187 @Override
188 public void removeAllViews() {
189 super.removeAllViews();
190 mWhichChild = 0;
191 mFirstTime = true;
192 }
193
194 @Override
195 public void removeView(View view) {
196 final int index = indexOfChild(view);
197 if (index >= 0) {
198 removeViewAt(index);
199 }
200 }
201
202 @Override
203 public void removeViewAt(int index) {
204 super.removeViewAt(index);
205 final int childCount = getChildCount();
206 if (childCount == 0) {
207 mWhichChild = 0;
208 mFirstTime = true;
209 } else if (mWhichChild >= childCount) {
210 // Displayed is above child count, so float down to top of stack
211 setDisplayedChild(childCount - 1);
212 } else if (mWhichChild == index) {
213 // Displayed was removed, so show the new child living in its place
214 setDisplayedChild(mWhichChild);
215 }
216 }
217
218 public void removeViewInLayout(View view) {
219 removeView(view);
220 }
221
222 public void removeViews(int start, int count) {
223 super.removeViews(start, count);
224 if (getChildCount() == 0) {
225 mWhichChild = 0;
226 mFirstTime = true;
227 } else if (mWhichChild >= start && mWhichChild < start + count) {
228 // Try showing new displayed child, wrapping if needed
229 setDisplayedChild(mWhichChild);
230 }
231 }
232
233 public void removeViewsInLayout(int start, int count) {
234 removeViews(start, count);
235 }
236
237 /**
238 * Returns the View corresponding to the currently displayed child.
239 *
240 * @return The View currently displayed.
241 *
242 * @see #getDisplayedChild()
243 */
244 public View getCurrentView() {
245 return getChildAt(mWhichChild);
246 }
247
248 /**
249 * Returns the current animation used to animate a View that enters the screen.
250 *
251 * @return An Animation or null if none is set.
252 *
253 * @see #setInAnimation(android.view.animation.Animation)
254 * @see #setInAnimation(android.content.Context, int)
255 */
256 public Animation getInAnimation() {
257 return mInAnimation;
258 }
259
260 /**
261 * Specifies the animation used to animate a View that enters the screen.
262 *
263 * @param inAnimation The animation started when a View enters the screen.
264 *
265 * @see #getInAnimation()
266 * @see #setInAnimation(android.content.Context, int)
267 */
268 public void setInAnimation(Animation inAnimation) {
269 mInAnimation = inAnimation;
270 }
271
272 /**
273 * Returns the current animation used to animate a View that exits the screen.
274 *
275 * @return An Animation or null if none is set.
276 *
277 * @see #setOutAnimation(android.view.animation.Animation)
278 * @see #setOutAnimation(android.content.Context, int)
279 */
280 public Animation getOutAnimation() {
281 return mOutAnimation;
282 }
283
284 /**
285 * Specifies the animation used to animate a View that exit the screen.
286 *
287 * @param outAnimation The animation started when a View exit the screen.
288 *
289 * @see #getOutAnimation()
290 * @see #setOutAnimation(android.content.Context, int)
291 */
292 public void setOutAnimation(Animation outAnimation) {
293 mOutAnimation = outAnimation;
294 }
295
296 /**
297 * Specifies the animation used to animate a View that enters the screen.
298 *
299 * @param context The application's environment.
300 * @param resourceID The resource id of the animation.
301 *
302 * @see #getInAnimation()
303 * @see #setInAnimation(android.view.animation.Animation)
304 */
305 public void setInAnimation(Context context, int resourceID) {
306 setInAnimation(AnimationUtils.loadAnimation(context, resourceID));
307 }
308
309 /**
310 * Specifies the animation used to animate a View that exit the screen.
311 *
312 * @param context The application's environment.
313 * @param resourceID The resource id of the animation.
314 *
315 * @see #getOutAnimation()
316 * @see #setOutAnimation(android.view.animation.Animation)
317 */
318 public void setOutAnimation(Context context, int resourceID) {
319 setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));
320 }
321
322 /**
323 * Indicates whether the current View should be animated the first time
324 * the ViewAnimation is displayed.
325 *
326 * @param animate True to animate the current View the first time it is displayed,
327 * false otherwise.
328 */
329 public void setAnimateFirstView(boolean animate) {
330 mAnimateFirstTime = animate;
331 }
332
333 @Override
334 public int getBaseline() {
335 return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();
336 }
337}