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