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 17 package android.widget; 18 19 20 import android.content.Context; 21 import android.content.res.TypedArray; 22 import android.util.AttributeSet; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.view.animation.Animation; 26 import 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 */ 35 public class ViewAnimator extends FrameLayout { 36 37 int mWhichChild = 0; 38 boolean mFirstTime = true; 39 boolean mAnimateFirstTime = true; 40 41 Animation mInAnimation; 42 Animation mOutAnimation; 43 ViewAnimator(Context context)44 public ViewAnimator(Context context) { 45 super(context); 46 initViewAnimator(); 47 } 48 ViewAnimator(Context context, AttributeSet attrs)49 public ViewAnimator(Context context, AttributeSet attrs) { 50 super(context, attrs); 51 52 TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator); 53 int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0); 54 if (resource > 0) { 55 setInAnimation(context, resource); 56 } 57 58 resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0); 59 if (resource > 0) { 60 setOutAnimation(context, resource); 61 } 62 a.recycle(); 63 64 initViewAnimator(); 65 } 66 initViewAnimator()67 private void initViewAnimator() { 68 mMeasureAllChildren = true; 69 } 70 71 /** 72 * Sets which child view will be displayed. 73 * 74 * @param whichChild the index of the child view to display 75 */ setDisplayedChild(int whichChild)76 public void setDisplayedChild(int whichChild) { 77 mWhichChild = whichChild; 78 if (whichChild >= getChildCount()) { 79 mWhichChild = 0; 80 } else if (whichChild < 0) { 81 mWhichChild = getChildCount() - 1; 82 } 83 boolean hasFocus = getFocusedChild() != null; 84 // This will clear old focus if we had it 85 showOnly(mWhichChild); 86 if (hasFocus) { 87 // Try to retake focus if we had it 88 requestFocus(FOCUS_FORWARD); 89 } 90 } 91 92 /** 93 * Returns the index of the currently displayed child view. 94 */ getDisplayedChild()95 public int getDisplayedChild() { 96 return mWhichChild; 97 } 98 99 /** 100 * Manually shows the next child. 101 */ showNext()102 public void showNext() { 103 setDisplayedChild(mWhichChild + 1); 104 } 105 106 /** 107 * Manually shows the previous child. 108 */ showPrevious()109 public void showPrevious() { 110 setDisplayedChild(mWhichChild - 1); 111 } 112 113 /** 114 * Shows only the specified child. The other displays Views exit the screen 115 * with the {@link #getOutAnimation() out animation} and the specified child 116 * enters the screen with the {@link #getInAnimation() in animation}. 117 * 118 * @param childIndex The index of the child to be shown. 119 */ showOnly(int childIndex)120 void showOnly(int childIndex) { 121 final int count = getChildCount(); 122 for (int i = 0; i < count; i++) { 123 final View child = getChildAt(i); 124 if (i == childIndex) { 125 if ((!mFirstTime || mAnimateFirstTime) && mInAnimation != null) { 126 child.startAnimation(mInAnimation); 127 } 128 child.setVisibility(View.VISIBLE); 129 mFirstTime = false; 130 } else { 131 if (mOutAnimation != null && child.getVisibility() == View.VISIBLE) { 132 child.startAnimation(mOutAnimation); 133 } else if (child.getAnimation() == mInAnimation) 134 child.clearAnimation(); 135 child.setVisibility(View.GONE); 136 } 137 } 138 } 139 140 @Override addView(View child, int index, ViewGroup.LayoutParams params)141 public void addView(View child, int index, ViewGroup.LayoutParams params) { 142 super.addView(child, index, params); 143 if (getChildCount() == 1) { 144 child.setVisibility(View.VISIBLE); 145 } else { 146 child.setVisibility(View.GONE); 147 } 148 } 149 150 @Override removeAllViews()151 public void removeAllViews() { 152 super.removeAllViews(); 153 mWhichChild = 0; 154 mFirstTime = true; 155 } 156 157 @Override removeView(View view)158 public void removeView(View view) { 159 final int index = indexOfChild(view); 160 if (index >= 0) { 161 removeViewAt(index); 162 } 163 } 164 165 @Override removeViewAt(int index)166 public void removeViewAt(int index) { 167 super.removeViewAt(index); 168 final int childCount = getChildCount(); 169 if (childCount == 0) { 170 mWhichChild = 0; 171 mFirstTime = true; 172 } else if (mWhichChild >= childCount) { 173 // Displayed is above child count, so float down to top of stack 174 setDisplayedChild(childCount - 1); 175 } else if (mWhichChild == index) { 176 // Displayed was removed, so show the new child living in its place 177 setDisplayedChild(mWhichChild); 178 } 179 } 180 removeViewInLayout(View view)181 public void removeViewInLayout(View view) { 182 removeView(view); 183 } 184 removeViews(int start, int count)185 public void removeViews(int start, int count) { 186 super.removeViews(start, count); 187 if (getChildCount() == 0) { 188 mWhichChild = 0; 189 mFirstTime = true; 190 } else if (mWhichChild >= start && mWhichChild < start + count) { 191 // Try showing new displayed child, wrapping if needed 192 setDisplayedChild(mWhichChild); 193 } 194 } 195 removeViewsInLayout(int start, int count)196 public void removeViewsInLayout(int start, int count) { 197 removeViews(start, count); 198 } 199 200 /** 201 * Returns the View corresponding to the currently displayed child. 202 * 203 * @return The View currently displayed. 204 * 205 * @see #getDisplayedChild() 206 */ getCurrentView()207 public View getCurrentView() { 208 return getChildAt(mWhichChild); 209 } 210 211 /** 212 * Returns the current animation used to animate a View that enters the screen. 213 * 214 * @return An Animation or null if none is set. 215 * 216 * @see #setInAnimation(android.view.animation.Animation) 217 * @see #setInAnimation(android.content.Context, int) 218 */ getInAnimation()219 public Animation getInAnimation() { 220 return mInAnimation; 221 } 222 223 /** 224 * Specifies the animation used to animate a View that enters the screen. 225 * 226 * @param inAnimation The animation started when a View enters the screen. 227 * 228 * @see #getInAnimation() 229 * @see #setInAnimation(android.content.Context, int) 230 */ setInAnimation(Animation inAnimation)231 public void setInAnimation(Animation inAnimation) { 232 mInAnimation = inAnimation; 233 } 234 235 /** 236 * Returns the current animation used to animate a View that exits the screen. 237 * 238 * @return An Animation or null if none is set. 239 * 240 * @see #setOutAnimation(android.view.animation.Animation) 241 * @see #setOutAnimation(android.content.Context, int) 242 */ getOutAnimation()243 public Animation getOutAnimation() { 244 return mOutAnimation; 245 } 246 247 /** 248 * Specifies the animation used to animate a View that exit the screen. 249 * 250 * @param outAnimation The animation started when a View exit the screen. 251 * 252 * @see #getOutAnimation() 253 * @see #setOutAnimation(android.content.Context, int) 254 */ setOutAnimation(Animation outAnimation)255 public void setOutAnimation(Animation outAnimation) { 256 mOutAnimation = outAnimation; 257 } 258 259 /** 260 * Specifies the animation used to animate a View that enters the screen. 261 * 262 * @param context The application's environment. 263 * @param resourceID The resource id of the animation. 264 * 265 * @see #getInAnimation() 266 * @see #setInAnimation(android.view.animation.Animation) 267 */ setInAnimation(Context context, int resourceID)268 public void setInAnimation(Context context, int resourceID) { 269 setInAnimation(AnimationUtils.loadAnimation(context, resourceID)); 270 } 271 272 /** 273 * Specifies the animation used to animate a View that exit the screen. 274 * 275 * @param context The application's environment. 276 * @param resourceID The resource id of the animation. 277 * 278 * @see #getOutAnimation() 279 * @see #setOutAnimation(android.view.animation.Animation) 280 */ setOutAnimation(Context context, int resourceID)281 public void setOutAnimation(Context context, int resourceID) { 282 setOutAnimation(AnimationUtils.loadAnimation(context, resourceID)); 283 } 284 285 /** 286 * Indicates whether the current View should be animated the first time 287 * the ViewAnimation is displayed. 288 * 289 * @param animate True to animate the current View the first time it is displayed, 290 * false otherwise. 291 */ setAnimateFirstView(boolean animate)292 public void setAnimateFirstView(boolean animate) { 293 mAnimateFirstTime = animate; 294 } 295 296 @Override getBaseline()297 public int getBaseline() { 298 return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline(); 299 } 300 } 301