diff --git a/src/api-impl/android/widget/ViewAnimator.java b/src/api-impl/android/widget/ViewAnimator.java index 6e38e391..fc8189ed 100644 --- a/src/api-impl/android/widget/ViewAnimator.java +++ b/src/api-impl/android/widget/ViewAnimator.java @@ -1,16 +1,344 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.widget; -import android.content.Context; -import android.util.AttributeSet; -import android.view.ViewGroup; -public class ViewAnimator extends ViewGroup { +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; + +/** + * Base class for a {@link FrameLayout} container that will perform animations + * when switching between its views. + * + * @attr ref android.R.styleable#ViewAnimator_inAnimation + * @attr ref android.R.styleable#ViewAnimator_outAnimation + * @attr ref android.R.styleable#ViewAnimator_animateFirstView + */ +public class ViewAnimator extends FrameLayout { + + int mWhichChild = 0; + boolean mFirstTime = true; + + boolean mAnimateFirstTime = true; + + Animation mInAnimation; + Animation mOutAnimation; + + public ViewAnimator(Context context) { + super(context); + initViewAnimator(context, null); + } public ViewAnimator(Context context, AttributeSet attrs) { super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ViewAnimator, + attrs, a, 0, 0); + + int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0); + if (resource > 0) { + setInAnimation(context, resource); + } + + resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0); + if (resource > 0) { + setOutAnimation(context, resource); + } + + boolean flag = a.getBoolean(com.android.internal.R.styleable.ViewAnimator_animateFirstView, true); + setAnimateFirstView(flag); + + a.recycle(); + + initViewAnimator(context, attrs); } - public void setDisplayedChild(int index) {} + /** + * Initialize this {@link ViewAnimator}, possibly setting + * {@link #setMeasureAllChildren(boolean)} based on {@link FrameLayout} flags. + */ + private void initViewAnimator(Context context, AttributeSet attrs) { + if (attrs == null) { + // For compatibility, always measure children when undefined. + mMeasureAllChildren = true; + return; + } - public int getDisplayedChild() { return 0; } + // For compatibility, default to measure children, but allow XML + // attribute to override. + final TypedArray a = context.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.FrameLayout); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.FrameLayout, + attrs, a, 0, 0); + final boolean measureAllChildren = a.getBoolean( + com.android.internal.R.styleable.FrameLayout_measureAllChildren, true); + setMeasureAllChildren(measureAllChildren); + a.recycle(); + } + + /** + * Sets which child view will be displayed. + * + * @param whichChild the index of the child view to display + */ + public void setDisplayedChild(int whichChild) { + mWhichChild = whichChild; + if (whichChild >= getChildCount()) { + mWhichChild = 0; + } else if (whichChild < 0) { + mWhichChild = getChildCount() - 1; + } + boolean hasFocus = getFocusedChild() != null; + // This will clear old focus if we had it + showOnly(mWhichChild); + if (hasFocus) { + // Try to retake focus if we had it + requestFocus(FOCUS_FORWARD); + } + } + + /** + * Returns the index of the currently displayed child view. + */ + public int getDisplayedChild() { + return mWhichChild; + } + + /** + * Manually shows the next child. + */ + public void showNext() { + setDisplayedChild(mWhichChild + 1); + } + + /** + * Manually shows the previous child. + */ + public void showPrevious() { + setDisplayedChild(mWhichChild - 1); + } + + /** + * Shows only the specified child. The other displays Views exit the screen, + * optionally with the with the {@link #getOutAnimation() out animation} and + * the specified child enters the screen, optionally with the + * {@link #getInAnimation() in animation}. + * + * @param childIndex The index of the child to be shown. + * @param animate Whether or not to use the in and out animations, defaults + * to true. + */ + void showOnly(int childIndex, boolean animate) { + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (i == childIndex) { + if (animate && mInAnimation != null) { + child.startAnimation(mInAnimation); + } + child.setVisibility(View.VISIBLE); + mFirstTime = false; + } else { + if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) { + child.startAnimation(mOutAnimation); + } else if (child.getAnimation() == mInAnimation) + child.clearAnimation(); + child.setVisibility(View.GONE); + } + } + } + /** + * Shows only the specified child. The other displays Views exit the screen + * with the {@link #getOutAnimation() out animation} and the specified child + * enters the screen with the {@link #getInAnimation() in animation}. + * + * @param childIndex The index of the child to be shown. + */ + void showOnly(int childIndex) { + final boolean animate = (!mFirstTime || mAnimateFirstTime); + showOnly(childIndex, animate); + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + super.addView(child, index, params); + if (getChildCount() == 1) { + child.setVisibility(View.VISIBLE); + } else { + child.setVisibility(View.GONE); + } + if (index >= 0 && mWhichChild >= index) { + // Added item above current one, increment the index of the displayed child + setDisplayedChild(mWhichChild + 1); + } + } + + @Override + public void removeAllViews() { + super.removeAllViews(); + mWhichChild = 0; + mFirstTime = true; + } + + @Override + public void removeView(View view) { + final int index = indexOfChild(view); + if (index >= 0) { + removeViewAt(index); + } + } + + @Override + public void removeViewAt(int index) { + super.removeViewAt(index); + final int childCount = getChildCount(); + if (childCount == 0) { + mWhichChild = 0; + mFirstTime = true; + } else if (mWhichChild >= childCount) { + // Displayed is above child count, so float down to top of stack + setDisplayedChild(childCount - 1); + } else if (mWhichChild == index) { + // Displayed was removed, so show the new child living in its place + setDisplayedChild(mWhichChild); + } + } + + public void removeViewInLayout(View view) { + removeView(view); + } + + /** + * Returns the View corresponding to the currently displayed child. + * + * @return The View currently displayed. + * + * @see #getDisplayedChild() + */ + public View getCurrentView() { + return getChildAt(mWhichChild); + } + + /** + * Returns the current animation used to animate a View that enters the screen. + * + * @return An Animation or null if none is set. + * + * @see #setInAnimation(android.view.animation.Animation) + * @see #setInAnimation(android.content.Context, int) + */ + public Animation getInAnimation() { + return mInAnimation; + } + + /** + * Specifies the animation used to animate a View that enters the screen. + * + * @param inAnimation The animation started when a View enters the screen. + * + * @see #getInAnimation() + * @see #setInAnimation(android.content.Context, int) + */ + public void setInAnimation(Animation inAnimation) { + mInAnimation = inAnimation; + } + + /** + * Returns the current animation used to animate a View that exits the screen. + * + * @return An Animation or null if none is set. + * + * @see #setOutAnimation(android.view.animation.Animation) + * @see #setOutAnimation(android.content.Context, int) + */ + public Animation getOutAnimation() { + return mOutAnimation; + } + + /** + * Specifies the animation used to animate a View that exit the screen. + * + * @param outAnimation The animation started when a View exit the screen. + * + * @see #getOutAnimation() + * @see #setOutAnimation(android.content.Context, int) + */ + public void setOutAnimation(Animation outAnimation) { + mOutAnimation = outAnimation; + } + + /** + * Specifies the animation used to animate a View that enters the screen. + * + * @param context The application's environment. + * @param resourceID The resource id of the animation. + * + * @see #getInAnimation() + * @see #setInAnimation(android.view.animation.Animation) + */ + public void setInAnimation(Context context, int resourceID) { + setInAnimation(AnimationUtils.loadAnimation(context, resourceID)); + } + + /** + * Specifies the animation used to animate a View that exit the screen. + * + * @param context The application's environment. + * @param resourceID The resource id of the animation. + * + * @see #getOutAnimation() + * @see #setOutAnimation(android.view.animation.Animation) + */ + public void setOutAnimation(Context context, int resourceID) { + setOutAnimation(AnimationUtils.loadAnimation(context, resourceID)); + } + + /** + * Returns whether the current View should be animated the first time the ViewAnimator + * is displayed. + * + * @return true if the current View will be animated the first time it is displayed, + * false otherwise. + * + * @see #setAnimateFirstView(boolean) + */ + public boolean getAnimateFirstView() { + return mAnimateFirstTime; + } + + /** + * Indicates whether the current View should be animated the first time + * the ViewAnimator is displayed. + * + * @param animate True to animate the current View the first time it is displayed, + * false otherwise. + */ + public void setAnimateFirstView(boolean animate) { + mAnimateFirstTime = animate; + } + + @Override + public int getBaseline() { + return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline(); + } }