blob: 90f61ca50d52727096d9565ea7d7a93dfb11f76c [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
Tor Norbye417ee5b2015-03-10 20:57:37 -070020import android.annotation.AnimRes;
Artur Satayeved5a6ae2019-12-10 17:47:54 +000021import android.compat.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
23import android.content.res.TypedArray;
24import android.util.AttributeSet;
25import android.view.View;
26import android.view.ViewGroup;
27import android.view.animation.Animation;
28import android.view.animation.AnimationUtils;
Ashley Rose55f9f922019-01-28 19:29:36 -050029import android.view.inspector.InspectableProperty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
31/**
32 * Base class for a {@link FrameLayout} container that will perform animations
33 * when switching between its views.
34 *
35 * @attr ref android.R.styleable#ViewAnimator_inAnimation
36 * @attr ref android.R.styleable#ViewAnimator_outAnimation
Mason Tangf70036b2010-06-14 17:47:24 -070037 * @attr ref android.R.styleable#ViewAnimator_animateFirstView
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 */
39public class ViewAnimator extends FrameLayout {
40
Mathew Inwood978c6e22018-08-21 15:58:55 +010041 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042 int mWhichChild = 0;
Mathew Inwood978c6e22018-08-21 15:58:55 +010043 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 boolean mFirstTime = true;
Mason Tangf70036b2010-06-14 17:47:24 -070045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 boolean mAnimateFirstTime = true;
47
48 Animation mInAnimation;
49 Animation mOutAnimation;
50
51 public ViewAnimator(Context context) {
52 super(context);
Jeff Sharkey1162fd72009-11-04 17:58:08 -080053 initViewAnimator(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 }
55
56 public ViewAnimator(Context context, AttributeSet attrs) {
57 super(context, attrs);
58
59 TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator);
Aurimas Liutikasfae34452019-07-22 13:03:36 -070060 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ViewAnimator,
61 attrs, a, 0, 0);
62
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);
64 if (resource > 0) {
65 setInAnimation(context, resource);
66 }
67
68 resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0);
69 if (resource > 0) {
70 setOutAnimation(context, resource);
71 }
Mason Tangf70036b2010-06-14 17:47:24 -070072
73 boolean flag = a.getBoolean(com.android.internal.R.styleable.ViewAnimator_animateFirstView, true);
74 setAnimateFirstView(flag);
75
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 a.recycle();
77
Jeff Sharkey1162fd72009-11-04 17:58:08 -080078 initViewAnimator(context, attrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 }
80
Jeff Sharkey1162fd72009-11-04 17:58:08 -080081 /**
82 * Initialize this {@link ViewAnimator}, possibly setting
83 * {@link #setMeasureAllChildren(boolean)} based on {@link FrameLayout} flags.
84 */
85 private void initViewAnimator(Context context, AttributeSet attrs) {
86 if (attrs == null) {
87 // For compatibility, always measure children when undefined.
88 mMeasureAllChildren = true;
89 return;
90 }
91
92 // For compatibility, default to measure children, but allow XML
93 // attribute to override.
94 final TypedArray a = context.obtainStyledAttributes(attrs,
95 com.android.internal.R.styleable.FrameLayout);
Aurimas Liutikasfae34452019-07-22 13:03:36 -070096 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.FrameLayout,
97 attrs, a, 0, 0);
Jeff Sharkey1162fd72009-11-04 17:58:08 -080098 final boolean measureAllChildren = a.getBoolean(
99 com.android.internal.R.styleable.FrameLayout_measureAllChildren, true);
100 setMeasureAllChildren(measureAllChildren);
101 a.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 }
Mason Tangf70036b2010-06-14 17:47:24 -0700103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 /**
105 * Sets which child view will be displayed.
Mason Tangf70036b2010-06-14 17:47:24 -0700106 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 * @param whichChild the index of the child view to display
108 */
Adam Cohen0b96a572011-02-10 15:56:16 -0800109 @android.view.RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 public void setDisplayedChild(int whichChild) {
111 mWhichChild = whichChild;
112 if (whichChild >= getChildCount()) {
113 mWhichChild = 0;
114 } else if (whichChild < 0) {
115 mWhichChild = getChildCount() - 1;
116 }
117 boolean hasFocus = getFocusedChild() != null;
118 // This will clear old focus if we had it
119 showOnly(mWhichChild);
120 if (hasFocus) {
121 // Try to retake focus if we had it
122 requestFocus(FOCUS_FORWARD);
123 }
124 }
Mason Tangf70036b2010-06-14 17:47:24 -0700125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 /**
127 * Returns the index of the currently displayed child view.
128 */
129 public int getDisplayedChild() {
130 return mWhichChild;
131 }
Mason Tangf70036b2010-06-14 17:47:24 -0700132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 /**
134 * Manually shows the next child.
135 */
Adam Cohen0b96a572011-02-10 15:56:16 -0800136 @android.view.RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 public void showNext() {
138 setDisplayedChild(mWhichChild + 1);
139 }
140
141 /**
142 * Manually shows the previous child.
143 */
Adam Cohen0b96a572011-02-10 15:56:16 -0800144 @android.view.RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 public void showPrevious() {
146 setDisplayedChild(mWhichChild - 1);
147 }
148
149 /**
Mason Tangf70036b2010-06-14 17:47:24 -0700150 * Shows only the specified child. The other displays Views exit the screen,
151 * optionally with the with the {@link #getOutAnimation() out animation} and
152 * the specified child enters the screen, optionally with the
153 * {@link #getInAnimation() in animation}.
154 *
155 * @param childIndex The index of the child to be shown.
156 * @param animate Whether or not to use the in and out animations, defaults
157 * to true.
158 */
Mathew Inwood978c6e22018-08-21 15:58:55 +0100159 @UnsupportedAppUsage
Mason Tangf70036b2010-06-14 17:47:24 -0700160 void showOnly(int childIndex, boolean animate) {
161 final int count = getChildCount();
162 for (int i = 0; i < count; i++) {
163 final View child = getChildAt(i);
164 if (i == childIndex) {
165 if (animate && mInAnimation != null) {
166 child.startAnimation(mInAnimation);
167 }
168 child.setVisibility(View.VISIBLE);
169 mFirstTime = false;
170 } else {
171 if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
172 child.startAnimation(mOutAnimation);
173 } else if (child.getAnimation() == mInAnimation)
174 child.clearAnimation();
175 child.setVisibility(View.GONE);
176 }
177 }
178 }
179 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 * Shows only the specified child. The other displays Views exit the screen
181 * with the {@link #getOutAnimation() out animation} and the specified child
182 * enters the screen with the {@link #getInAnimation() in animation}.
183 *
184 * @param childIndex The index of the child to be shown.
185 */
186 void showOnly(int childIndex) {
Mason Tangf70036b2010-06-14 17:47:24 -0700187 final boolean animate = (!mFirstTime || mAnimateFirstTime);
188 showOnly(childIndex, animate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 }
190
191 @Override
192 public void addView(View child, int index, ViewGroup.LayoutParams params) {
193 super.addView(child, index, params);
194 if (getChildCount() == 1) {
195 child.setVisibility(View.VISIBLE);
196 } else {
197 child.setVisibility(View.GONE);
198 }
Chet Haasebaea2442011-12-20 07:08:51 -0800199 if (index >= 0 && mWhichChild >= index) {
200 // Added item above current one, increment the index of the displayed child
201 setDisplayedChild(mWhichChild + 1);
202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 }
204
205 @Override
206 public void removeAllViews() {
207 super.removeAllViews();
208 mWhichChild = 0;
209 mFirstTime = true;
210 }
211
212 @Override
213 public void removeView(View view) {
214 final int index = indexOfChild(view);
215 if (index >= 0) {
216 removeViewAt(index);
217 }
218 }
219
220 @Override
221 public void removeViewAt(int index) {
222 super.removeViewAt(index);
223 final int childCount = getChildCount();
224 if (childCount == 0) {
225 mWhichChild = 0;
226 mFirstTime = true;
227 } else if (mWhichChild >= childCount) {
228 // Displayed is above child count, so float down to top of stack
229 setDisplayedChild(childCount - 1);
230 } else if (mWhichChild == index) {
231 // Displayed was removed, so show the new child living in its place
232 setDisplayedChild(mWhichChild);
233 }
234 }
235
236 public void removeViewInLayout(View view) {
237 removeView(view);
238 }
239
240 public void removeViews(int start, int count) {
241 super.removeViews(start, count);
242 if (getChildCount() == 0) {
243 mWhichChild = 0;
244 mFirstTime = true;
245 } else if (mWhichChild >= start && mWhichChild < start + count) {
246 // Try showing new displayed child, wrapping if needed
247 setDisplayedChild(mWhichChild);
248 }
249 }
250
251 public void removeViewsInLayout(int start, int count) {
252 removeViews(start, count);
253 }
254
255 /**
256 * Returns the View corresponding to the currently displayed child.
257 *
258 * @return The View currently displayed.
259 *
260 * @see #getDisplayedChild()
261 */
262 public View getCurrentView() {
263 return getChildAt(mWhichChild);
264 }
265
266 /**
267 * Returns the current animation used to animate a View that enters the screen.
268 *
269 * @return An Animation or null if none is set.
270 *
271 * @see #setInAnimation(android.view.animation.Animation)
272 * @see #setInAnimation(android.content.Context, int)
273 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500274 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 public Animation getInAnimation() {
276 return mInAnimation;
277 }
278
279 /**
280 * Specifies the animation used to animate a View that enters the screen.
281 *
282 * @param inAnimation The animation started when a View enters the screen.
283 *
284 * @see #getInAnimation()
285 * @see #setInAnimation(android.content.Context, int)
286 */
287 public void setInAnimation(Animation inAnimation) {
288 mInAnimation = inAnimation;
289 }
290
291 /**
292 * Returns the current animation used to animate a View that exits the screen.
293 *
294 * @return An Animation or null if none is set.
295 *
296 * @see #setOutAnimation(android.view.animation.Animation)
297 * @see #setOutAnimation(android.content.Context, int)
298 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500299 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 public Animation getOutAnimation() {
301 return mOutAnimation;
302 }
303
304 /**
305 * Specifies the animation used to animate a View that exit the screen.
306 *
307 * @param outAnimation The animation started when a View exit the screen.
308 *
309 * @see #getOutAnimation()
310 * @see #setOutAnimation(android.content.Context, int)
311 */
312 public void setOutAnimation(Animation outAnimation) {
313 mOutAnimation = outAnimation;
314 }
315
316 /**
317 * Specifies the animation used to animate a View that enters the screen.
318 *
319 * @param context The application's environment.
320 * @param resourceID The resource id of the animation.
321 *
322 * @see #getInAnimation()
323 * @see #setInAnimation(android.view.animation.Animation)
324 */
Tor Norbye417ee5b2015-03-10 20:57:37 -0700325 public void setInAnimation(Context context, @AnimRes int resourceID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 setInAnimation(AnimationUtils.loadAnimation(context, resourceID));
327 }
328
329 /**
330 * Specifies the animation used to animate a View that exit the screen.
331 *
332 * @param context The application's environment.
333 * @param resourceID The resource id of the animation.
334 *
335 * @see #getOutAnimation()
336 * @see #setOutAnimation(android.view.animation.Animation)
337 */
Tor Norbye417ee5b2015-03-10 20:57:37 -0700338 public void setOutAnimation(Context context, @AnimRes int resourceID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));
340 }
341
342 /**
Chet Haase201501f2012-08-30 09:51:08 -0700343 * Returns whether the current View should be animated the first time the ViewAnimator
344 * is displayed.
345 *
346 * @return true if the current View will be animated the first time it is displayed,
347 * false otherwise.
348 *
349 * @see #setAnimateFirstView(boolean)
350 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500351 @InspectableProperty
Chet Haase201501f2012-08-30 09:51:08 -0700352 public boolean getAnimateFirstView() {
353 return mAnimateFirstTime;
354 }
355
356 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 * Indicates whether the current View should be animated the first time
Chet Haase201501f2012-08-30 09:51:08 -0700358 * the ViewAnimator is displayed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 *
360 * @param animate True to animate the current View the first time it is displayed,
361 * false otherwise.
362 */
363 public void setAnimateFirstView(boolean animate) {
364 mAnimateFirstTime = animate;
365 }
366
367 @Override
368 public int getBaseline() {
369 return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();
370 }
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800371
372 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800373 public CharSequence getAccessibilityClassName() {
374 return ViewAnimator.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376}