anim
slide_bottom_out.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="3000" android:fromYDelta="0.0" android:toYDelta="100.0%p" /> </set>
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="3000" android:fromYDelta="-100.0%p" android:toYDelta="0.0" /> </set>
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="3000" android:fromXDelta="-100.0%p" android:toXDelta="0.0" /> </set>
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="3000" android:fromXDelta="0.0" android:toXDelta="-100.0%p" /> </set>
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="3000" android:fromXDelta="100.0%p" android:toXDelta="0.0" /> </set>
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="3000" android:fromXDelta="0.0" android:toXDelta="100.0%p" /> </set>
import java.util.ArrayList; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.ViewFlipper; public class TileAnimator extends TileAnimatorLayout { private static final String TAG = "TileAnimator"; private static final boolean LOGD = false; private static final int DEFAULT_INTERVAL = 5000; private int mFlipInterval = DEFAULT_INTERVAL; private boolean mAutoStart = false; private boolean mRunning = false; private boolean mStarted = false; private boolean mVisible = false; private boolean mUserPresent = true; private ArrayList<TilesFrameEntity> entities = new ArrayList<TilesFrameEntity>(); public TileAnimator(Context context) { super(context); } public TileAnimator(Context context, AttributeSet attrs) { super(context, attrs); } public ArrayList<TilesFrameEntity> getEntities() { return entities; } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (Intent.ACTION_SCREEN_OFF.equals(action)) { mUserPresent = false; updateRunning(); } else if (Intent.ACTION_USER_PRESENT.equals(action)) { mUserPresent = true; updateRunning(false); } } }; @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_USER_PRESENT); getContext().registerReceiver(mReceiver, filter); if (mAutoStart) { startFlipping(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mVisible = false; getContext().unregisterReceiver(mReceiver); updateRunning(); } @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); mVisible = visibility == VISIBLE; updateRunning(false); } /** * How long to wait before flipping to the next view * * @param milliseconds * time in milliseconds */ public void setFlipInterval(int milliseconds) { mFlipInterval = milliseconds; } /** * Start a timer to cycle through child views */ public void startFlipping() { mStarted = true; updateRunning(); } /** * No more flips */ public void stopFlipping() { mStarted = false; updateRunning(); } @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); event.setClassName(ViewFlipper.class.getName()); } @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(ViewFlipper.class.getName()); } /** * Internal method to start or stop dispatching flip {@link Message} based * on {@link #mRunning} and {@link #mVisible} state. */ private void updateRunning() { updateRunning(true); } /** * Internal method to start or stop dispatching flip {@link Message} based * on {@link #mRunning} and {@link #mVisible} state. * * @param flipNow * Determines whether or not to execute the animation now, in * addition to queuing future flips. If omitted, defaults to * true. */ private void updateRunning(boolean flipNow) { boolean running = mVisible && mStarted && mUserPresent; if (running != mRunning) { if (running) { showOnly(mWhichChild, flipNow); Message msg = mHandler.obtainMessage(FLIP_MSG); int interval = getInterval(mWhichChild); mHandler.sendMessageDelayed(msg, interval); } else { mHandler.removeMessages(FLIP_MSG); } mRunning = running; } if (LOGD) { Log.d(TAG, "updateRunning() mVisible=" + mVisible + ", mStarted=" + mStarted + ", mUserPresent=" + mUserPresent + ", mRunning=" + mRunning); } } @Override public void addView(View child) { super.addView(child); } private int parse2Int(String s) { int res = 5; try { res = Integer.parseInt(s); if (res < 5) { res = 5; } return res * 1000; } catch (Exception e) { Log.e(TAG, "parse2Int", e); } return mFlipInterval; } /** * Returns true if the child views are flipping. */ public boolean isFlipping() { return mStarted; } /** * 添加瓷片元素 * @param entities * @param type */ public void setTilesFrame(ArrayList<TilesFrameEntity> entities, int type) { stopFlipping(); this.entities = entities; this.removeAllViews(); for (TilesFrameEntity e : entities) { ImageView img = new ImageView(getContext()); if (e.mDrawable != null) { img.setBackgroundDrawable(e.mDrawable); } img.setScaleType(ScaleType.FIT_XY); this.addView(img, new FrameLayout.LayoutParams( FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT)); } mAutoStart = true; startFlipping(); } /** * 获取间隔时间 * @param next * @return */ private int getInterval(int next) { if (next >= getChildCount()) { next = 0; } else if (next < 0) { next = getChildCount() - 1; } if (entities != null && !entities.isEmpty() && next >= 0 && next < entities.size()) { return parse2Int(entities.get(next).getDuration()); } return mFlipInterval; } /** * Returns true if this view automatically calls {@link #startFlipping()} * when it becomes attached to a window. */ public boolean isAutoStart() { return mAutoStart; } private final int FLIP_MSG = 1; private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == FLIP_MSG) { if (mRunning) { showNext(); msg = obtainMessage(FLIP_MSG); int interval = getInterval(mWhichChild + 1); sendMessageDelayed(msg, interval); } } } }; }
import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; import android.widget.ViewAnimator; public class TileAnimatorLayout extends FrameLayout { public TileAnimatorLayout(Context context) { super(context); initViewAnimator(context, null); } public TileAnimatorLayout(Context context, AttributeSet attrs) { super(context, attrs); initViewAnimator(context, attrs); } int mWhichChild = 0; boolean mFirstTime = true; boolean mAnimateFirstTime = true; Animation mInAnimation; Animation mOutAnimation; boolean mMeasureAllChildren = true; /** * 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; } // TypedArray a = context.obtainStyledAttributes(attrs, // R.styleable.tilesFrameAnimation); // int resource = a.getResourceId( // R.styleable.tilesFrameAnimation_inAnimation, 0); // if (resource > 0) { // setInAnimation(context, resource); // } // // resource = a.getResourceId( // R.styleable.tilesFrameAnimation_outAnimation, 0); // if (resource > 0) { // setOutAnimation(context, resource); // } setAnimateFirstView(true); // a.recycle(); setMeasureAllChildren(true); } /** * 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 && count > 1) { child.startAnimation(mInAnimation); } child.setVisibility(View.VISIBLE); mFirstTime = false; } else { if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) { if (count > 1) { 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) */ 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(); } @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); event.setClassName(ViewAnimator.class.getName()); } @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(ViewAnimator.class.getName()); } }
TileAnimatorLayout是ViewAnimator的源码,唯一的不同就是增加了个数为一个时,不进行动画的判断,另外可以使TileAnimator调用showOnly(mWhichChild, flipNow)方法。