378 lines
12 KiB
Java
378 lines
12 KiB
Java
/*
|
|
* 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.annotation.AnimRes;
|
|
import android.compat.annotation.UnsupportedAppUsage;
|
|
import android.content.Context;
|
|
import android.content.res.TypedArray;
|
|
import android.os.Build;
|
|
import android.util.AttributeSet;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.animation.Animation;
|
|
import android.view.animation.AnimationUtils;
|
|
import android.view.inspector.InspectableProperty;
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
@UnsupportedAppUsage
|
|
int mWhichChild = 0;
|
|
@UnsupportedAppUsage
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
// 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
|
|
*/
|
|
@android.view.RemotableViewMethod
|
|
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.
|
|
*/
|
|
@android.view.RemotableViewMethod
|
|
public void showNext() {
|
|
setDisplayedChild(mWhichChild + 1);
|
|
}
|
|
|
|
/**
|
|
* Manually shows the previous child.
|
|
*/
|
|
@android.view.RemotableViewMethod
|
|
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.
|
|
*/
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
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);
|
|
}
|
|
|
|
public void removeViews(int start, int count) {
|
|
super.removeViews(start, count);
|
|
if (getChildCount() == 0) {
|
|
mWhichChild = 0;
|
|
mFirstTime = true;
|
|
} else if (mWhichChild >= start && mWhichChild < start + count) {
|
|
// Try showing new displayed child, wrapping if needed
|
|
setDisplayedChild(mWhichChild);
|
|
}
|
|
}
|
|
|
|
public void removeViewsInLayout(int start, int count) {
|
|
removeViews(start, count);
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
*/
|
|
@InspectableProperty
|
|
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)
|
|
*/
|
|
@InspectableProperty
|
|
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, @AnimRes 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, @AnimRes 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)
|
|
*/
|
|
@InspectableProperty
|
|
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();
|
|
}
|
|
|
|
@Override
|
|
public CharSequence getAccessibilityClassName() {
|
|
return ViewAnimator.class.getName();
|
|
}
|
|
}
|