ViewAnimator.java revision baea244a9fadd6fc30c1491085d01e1fe30f8ca4
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 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 34 * @attr ref android.R.styleable#ViewAnimator_animateFirstView 35 */ 36public 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 46 public ViewAnimator(Context context) { 47 super(context); 48 initViewAnimator(context, null); 49 } 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 } 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 */ 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 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 */ 119 public int getDisplayedChild() { 120 return mWhichChild; 121 } 122 123 /** 124 * Manually shows the next child. 125 */ 126 @android.view.RemotableViewMethod 127 public void showNext() { 128 setDisplayedChild(mWhichChild + 1); 129 } 130 131 /** 132 * Manually shows the previous child. 133 */ 134 @android.view.RemotableViewMethod 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 */ 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 */ 175 void showOnly(int childIndex) { 176 final boolean animate = (!mFirstTime || mAnimateFirstTime); 177 showOnly(childIndex, animate); 178 } 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 if (index >= 0 && mWhichChild >= index) { 189 // Added item above current one, increment the index of the displayed child 190 setDisplayedChild(mWhichChild + 1); 191 } 192 } 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} 345