Android 控件自动“移入、暂停、移出”效果的实现

一个常见的效果:控件自动移入屏幕,停留几秒,再移出屏幕。项目中想做,但没找到合适的教程,于是自己写了一个工具类实现这个效果。本人初学android,实现方法肯定不是最优的,这只是一个没有办法的办法。构思很简单:两个动画,一个移入,一个移出,两个动画间插入一个计时器,以下是代码:
动画类(该类可以实现多个控件的同步动画,只要把所有控件传入构造方法即可,如果要执行不同的动画,各个控件单独调用就可以了,同时设置了一个开关用于控制是否执行“移出”的动作):
package net.jackie.util;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.view.animation.Animation.AnimationListener;

/**
 * @author jackie
 *
 */
public class MoveInAndOutAnim {

	private static final String TAG = "MoveInAndOutAnim";
	
	private int animDuration;
	private int fromXDelta;
	private int toXDelta;
	private int fromYDelta;
	private int toYDelt;
	private int keepDuration;
	private View[] views;
	private TranslateAnimation mMoveInAnim;
	private TranslateAnimation mMoveOutAnim;
	private TimerManager tm;
	private boolean processMoveOutAnim;
	
	/**
	 * 
	 * @param animDuration Duration of animation
	 * @param fromXDelta Change in X coordinate to apply at the start of the animation(generally 0)
	 * @param toXDelta Change in X coordinate to apply at the end of the animation
	 * 					(if you want to make a horizontal moving, move to right if positive value, move to left if negative value)
	 * @param fromYDelta Change in Y coordinate to apply at the start of the animation(generally 0)
	 * @param toYDelt Change in Y coordinate to apply at the end of the animation
	 * 					(if you want to make a vertical moving, move to bottom if positive value, move to top if negative value)
	 * @param keepDuration Duration to keep the Views displaying
	 * @param processMoveOutAnim whether to process the move out animation
	 * @param views Views to process the animation
	 */
	public MoveInAndOutAnim(int animDuration, int fromXDelta, int toXDelta,
			int fromYDelta, int toYDelt, int keepDuration, boolean processMoveOutAnim, View... views) {
		this.animDuration = animDuration;
		this.fromXDelta = fromXDelta;
		this.toXDelta = toXDelta;
		this.fromYDelta = fromYDelta;
		this.toYDelt = toYDelt;
		this.keepDuration = keepDuration;
		this.views = views;
		this.processMoveOutAnim = processMoveOutAnim;
		
		initMoveOutAnim();
		initMoveInAnim();
		initTimer();
	}
	
	private void initMoveInAnim() {
		mMoveInAnim = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelt);
		mMoveInAnim.setDuration(animDuration);
		mMoveInAnim.setFillAfter(true);
		mMoveInAnim.setAnimationListener(new AnimationListener() {
			@Override
			public void onAnimationStart(Animation animation) {
				
			}
			@Override
			public void onAnimationEnd(Animation animation) {
				if (processMoveOutAnim) {
					tm.startTimer();
				}
			}
			@Override
			public void onAnimationRepeat(Animation animation) {
				
			}
		});
	}
	
	private void initMoveOutAnim() {
		mMoveOutAnim = new TranslateAnimation(toXDelta, fromXDelta, toYDelt, fromYDelta);
		mMoveOutAnim.setDuration(animDuration);
		mMoveOutAnim.setFillBefore(true);
		mMoveOutAnim.setAnimationListener(new AnimationListener() {
			@Override
			public void onAnimationStart(Animation animation) {
				
			}
			@Override
			public void onAnimationEnd(Animation animation) {
				clearAnim();
			}
			@Override
			public void onAnimationRepeat(Animation animation) {
				
			}
		});
	}
	
	@SuppressLint("HandlerLeak")
	private void initTimer() {
		// Initial timer to control closing of 'Too Short' dialog
		// In fact, delay controls how long to keep the Views, so do not set it to 0
		tm = new TimerManager(keepDuration, keepDuration);
		Handler mHandler = new Handler() {
			@Override
			public void handleMessage(
					Message msg) {
				super.handleMessage(msg);
				
				switch(msg.what) {
				case TimerManager.LOAD_PROGRESS :
					for(View view : views) {
						view.startAnimation(mMoveOutAnim);
					}
					tm.closeTimer();
					break;
				case TimerManager.CLOSE_PROGRESS :
					// Do nothing
					Log.d(TAG, "Timer for 'Keep View' is closed.");
					break;
				}
			}
		};
		tm.setHandler(mHandler);
	}
	
	public void startAnim() {
		for(View view : views) {
			view.startAnimation(mMoveInAnim);
		}
	}
	
	private void clearAnim() {
		for(View view : views) {
			view.clearAnimation();
		}
	}
}


以上动画中用到了一个计时器类TimerManager,也是一个工具类,封装了一个计时器,可以单独用于计时器实例的取得:
package net.jackie.util;

import java.util.Timer;
import java.util.TimerTask;

import android.os.Handler;
import android.os.Message;

/**
 * Generate a timer object with specified 'delay' and 'period', 
 * you can handle events with 'TimerManager.LOAD_PROGRESS' 
 * and 'TimerManager.CLOSE_PROGRESS', then do your progress.
 * If you want to get 'timerId', just get it from 'arg1'
 * 
 * @author jackie
 *
 */
public class TimerManager {

	private Handler mHandler;
	/** Timer **/  
    private Timer timer = null;  
    /** TimerTask **/  
    private TimerTask timerTask = null;
    /** Delay Time in milliseconds **/  
    private int mDelay;
    /** Period in milliseconds **/  
    private int mPeriod;
    /** Timer in progressing flag **/  
    public static final int LOAD_PROGRESS = 0;  
    /** Timer close flag **/  
    public static final int CLOSE_PROGRESS = 1;  
    /** TimerId **/  
    private int mTimerId = 0;
    
    public TimerManager(int delay, int period) {
    	this.mDelay = delay;
    	this.mPeriod = period;
    }
    
    /**
     * 
     * @param handler your own handler to handle the events from this timer
     * @param delay amount of time in milliseconds before first execution
     * @param period amount of time in milliseconds between subsequent executions
     */
    public TimerManager(Handler handler, int delay, int period) {
    	this.mHandler = handler;
    	this.mDelay = delay;
    	this.mPeriod = period;
    }
    
	public void startTimer() {
        if (timerTask == null) {
            timerTask = new TimerTask() {
                @Override  
                public void run() {
                    Message msg = new Message();  
                    msg.what = LOAD_PROGRESS;  
                    msg.arg1 = (int) (++mTimerId);
                    if (mHandler != null) {
                    	mHandler.sendMessage(msg);
                    }
                }  
            };
            timer = new Timer();  
            timer.schedule(timerTask, mDelay, mPeriod);  
        }  
    }
  
    public void closeTimer() {
        if (timer != null) {  
            timer.cancel();  
            timer = null;  
        }  
        if (timerTask != null) {  
            timerTask = null;  
        }  
        mTimerId = 0;
        if (mHandler != null) {
        	mHandler.sendEmptyMessage(CLOSE_PROGRESS);
        }
    }
    
    public void setHandler(Handler handler) {
    	this.mHandler = handler;
    }
}


用法很简单,只要构造MoveInAndOutAnim,并调用startAnim方法即可:
MoveInAndOutAnim anim = new MoveInAndOutAnim(
								ANIMATION_DURATION, 0, 0, 0, topBarHeight,
								SHOW_ADDRESS_DELAY, true, showAddressLL, mLocationIv);
						anim.startAnim();

showAddressLL和mLocationIv就是我自己的两个控件,一个是LinearLayout一个是ImageView,我需要他们两个同步执行动画效果。

猜你喜欢

转载自lovelease.iteye.com/blog/2113572