1. 程式人生 > >Android 仿QQ分組管理可拖動Item的ListView(附原始碼)

Android 仿QQ分組管理可拖動Item的ListView(附原始碼)

趁著週一休息,更新一下部落格。最近專案中使用到了分組管理,需要實現Listview的Item拖動處理。查略一下資料和借鑑了別人的程式碼將功能實現了。現在整理一下程式碼,方便自己以後學習具體思路如下

重寫ListView的onInterceptTouchEvent方法進行控制元件的touch事件攔截

這個方法的作用很簡單:當我們摁下的如果是可拖拽的圖示,那麼進行初始化該Item的映像試檢視。

同時在拖動中判斷拖動的距離,具體檢視下面程式碼。不是則不進行處理。程式碼如下(程式碼註釋非常清楚,如果還有不懂的地方可以在下面留言,我們一起討論,或者下載原始碼,自己好好研究一下)

package com.pengguichu.testdraglistview.listview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;

import com.pengguichu.testdraglistview.R;
import com.pengguichu.testdraglistview.adapter.DragListAdapter;
import com.pengguichu.testdraglistview.entiy.DragItemInfo;

/**
 * 自定義可拖動Item排序ListView
 * 
 * @author guichupeng
 * 
 */
@SuppressLint({ "NewApi", "HandlerLeak" })
public class DragListView extends ListView {

	private ImageView mDragImageView;// 被拖拽的項(item),其實就是一個ImageView
	private int mStartPosition;// 手指拖動項原始在列表中的位置
	private int mDragPosition;// 手指點選準備拖動的時候,當前拖動項在列表中的位置
	private int mLastPosition;// 手指點選準備拖動的時候,當前拖動項在列表中的位置
	private int mDragPoint;// 在當前資料項中的位置
	private int mDragOffset;// 當前檢視和螢幕的距離(這裡只使用了y方向上)
	private int mUpScrollBounce;// 拖動的時候,開始向上滾動的邊界
	private int mDownScrollBounce;// 拖動的時候,開始向下滾動的邊界
	private final static int mStep = 1;// ListView 滑動步伐
	private int mCurrentStep;// 當前步伐
	private DragItemInfo mDragItemInfo;// 用於存放Item資訊的物件
	private int mItemVerticalSpacing = 0;// Item垂直區域空間
	private int mHoldPosition;// 標記最後停靠的Position

	/** windows視窗控制類 */
	private WindowManager mWindowManager;
	/** 用於控制拖拽項的顯示的引數 */
	private WindowManager.LayoutParams mWindowParams;
	/** 停止狀態 */
	public static final int MSG_DRAG_STOP = 0x1001;
	/** 移動狀態 */
	public static final int MSG_DRAG_MOVE = 0x1002;
	/** 動畫時長(一個動畫的耗時) */
	private static final int ANIMATION_DURATION = 200;
	/** 標識是否上鎖 */
	private boolean isLock;
	/** 標識是否處於移動狀態 */
	private boolean isMoving = false;
	/** 是否拖動Item */
	private boolean isDragItemMoving = false;
	/** 標識是否獲取到間距 */
	private boolean bHasGetSapcing = false;

	public DragListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		setLayerType(View.LAYER_TYPE_HARDWARE, null);
		mDragItemInfo = new DragItemInfo();
		init();
	}

	/**
	 * 初始化
	 */
	private void init() {
		mWindowManager = (WindowManager) getContext()
				.getSystemService("window");
	}

	/**
	 * 接收訊息並完成對應動作
	 */
	Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {

			switch (msg.what) {
			case MSG_DRAG_STOP:// 停止
				stopDrag();
				onDrop(msg.arg1);
				break;
			case MSG_DRAG_MOVE:// 移動
				onDrag(msg.arg1);
				break;
			}

		};
	};

	/**
	 * 獲取間距--獲取上下滾動間距
	 */
	private void getSpacing() {
		bHasGetSapcing = true;

		mUpScrollBounce = getHeight() / 3;// 取得向上滾動的邊際,大概為該控制元件的1/3
		mDownScrollBounce = getHeight() * 2 / 3;// 取得向下滾動的邊際,大概為該控制元件的2/3

		int[] firstTempLocation = new int[2];
		int[] secondTempLocation = new int[2];

		ViewGroup firstItemView = (ViewGroup) getChildAt(0);// 第一行
		ViewGroup secondItemView = (ViewGroup) getChildAt(1);// 第二行

		if (firstItemView != null) {
			firstItemView.getLocationOnScreen(firstTempLocation);
		} else {
			return;
		}

		if (secondItemView != null) {
			secondItemView.getLocationOnScreen(secondTempLocation);
			mItemVerticalSpacing = Math.abs(secondTempLocation[1]
					- firstTempLocation[1]);
		} else {
			return;
		}
	}

	/***
	 * touch事件攔截 在這裡我進行相應攔截,
	 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		// 按下
		if (ev.getAction() == MotionEvent.ACTION_DOWN && !isLock && !isMoving
				&& !isDragItemMoving) {

			int x = (int) ev.getX();// 獲取相對與ListView的x座標
			int y = (int) ev.getY();// 獲取相應與ListView的y座標
			mLastPosition = mStartPosition = mDragPosition = pointToPosition(x,
					y);

			// 無效不進行處理
			if (mDragPosition == AdapterView.INVALID_POSITION) {
				return super.onInterceptTouchEvent(ev);
			}

			if (false == bHasGetSapcing) {
				getSpacing();
			}

			// 獲取當前位置的檢視(可見狀態)
			ViewGroup dragger = (ViewGroup) getChildAt(mDragPosition
					- getFirstVisiblePosition());

			DragListAdapter adapter = (DragListAdapter) getAdapter();

			mDragItemInfo.obj = adapter.getItem(mDragPosition
					- getFirstVisiblePosition());

			// 獲取到的dragPoint其實就是在你點選指定item項中的高度.
			mDragPoint = y - dragger.getTop();
			// 這個值是固定的:其實就是ListView這個控制元件與螢幕最頂部的距離(一般為標題欄+狀態列).
			mDragOffset = (int) (ev.getRawY() - y);

			// 獲取可拖拽的圖示
			View draggerIcon = dragger.findViewById(R.id.drag_item_image);
			if (draggerIcon.getVisibility() == View.VISIBLE) {// 只有在按鈕為可見的情況下才允許移動

				// x > dragger.getLeft() - 20這句話為了更好的觸控(-20可以省略)
				if (draggerIcon != null && x > draggerIcon.getLeft() - 20) {

					dragger.destroyDrawingCache();
					dragger.setDrawingCacheEnabled(true);// 開啟cache.
					dragger.setBackgroundColor(0xffefefef);
					Bitmap bm = Bitmap.createBitmap(dragger
							.getDrawingCache(true));// 根據cache建立一個新的bitmap物件.
					hideDropItem();
					adapter.setInvisiblePosition(mStartPosition);
					adapter.notifyDataSetChanged();
					startDrag(bm, y);// 初始化影像
					isMoving = false;

					adapter.copyList();
				}
			}
		}

		return super.onInterceptTouchEvent(ev);
	}

	/**
	 * 獲取依個縮放動畫
	 * 
	 * @return
	 */
	public Animation getScaleAnimation() {
		Animation scaleAnimation = new ScaleAnimation(0.0f, 0.0f, 0.0f, 0.0f,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		scaleAnimation.setFillAfter(true);
		return scaleAnimation;
	}

	/**
	 * 隱藏下降的Item
	 */
	private void hideDropItem() {
		final DragListAdapter adapter = (DragListAdapter) this.getAdapter();
		adapter.showDropItem(false);
	}

	/**
	 * 觸控事件處理
	 */
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// item的view不為空,且獲取的dragPosition有效
		if (mDragImageView != null && mDragPosition != INVALID_POSITION
				&& !isLock) {

			int action = ev.getAction();
			switch (action) {

			case MotionEvent.ACTION_UP:
				int upY = (int) ev.getY();
				stopDrag();
				onDrop(upY);
				break;
			case MotionEvent.ACTION_MOVE:
				int moveY = (int) ev.getY();
				onDrag(moveY);
				itemMoveAnimation(moveY);
				break;
			case MotionEvent.ACTION_DOWN:
				break;

			}

			return true;// 取消ListView滑動.

		}

		return super.onTouchEvent(ev);
	}

	/**
	 * 是否為相同方向拖動的標記
	 */
	private boolean isSameDragDirection = true;
	/**
	 * 移動方向的標記,-1為預設值,0表示向下移動,1表示向上移動
	 */
	private int lastFlag = -1;
	private int mFirstVisiblePosition, mLastVisiblePosition;// 第一個、最後一個的位置
	private int turnUpPosition, turnDownPosition;// 向上、下的位置

	/**
	 * 動態改變Item內容
	 * 
	 * @param last
	 *            // 最後一項的位置
	 * @param current
	 *            // 當前位置
	 */
	private void onChangeCopy(int last, int current) {

		DragListAdapter adapter = (DragListAdapter) getAdapter();
		if (last != current) {// 判斷是否移動到最後一項
			adapter.exchangeCopy(last, current);
		}

	}

	/**
	 * Item移動動畫
	 * 
	 * @param y
	 */
	private void itemMoveAnimation(int y) {

		final DragListAdapter adapter = (DragListAdapter) getAdapter();
		int tempPosition = pointToPosition(0, y);

		if (tempPosition == INVALID_POSITION || tempPosition == mLastPosition) {
			return;
		}

		mFirstVisiblePosition = getFirstVisiblePosition();
		mDragPosition = tempPosition;
		onChangeCopy(mLastPosition, mDragPosition);
		int MoveNum = tempPosition - mLastPosition;// 計算移動項--移動距離
		int count = Math.abs(MoveNum);

		for (int i = 1; i <= count; i++) {
			int xAbsOffset, yAbsOffset;
			// 向下拖動
			if (MoveNum > 0) {

				if (lastFlag == -1) {
					lastFlag = 0;
					isSameDragDirection = true;
				}

				if (lastFlag == 1) {
					turnUpPosition = tempPosition;
					lastFlag = 0;
					isSameDragDirection = !isSameDragDirection;
				}

				if (isSameDragDirection) {
					mHoldPosition = mLastPosition + 1;
				} else {
					if (mStartPosition < tempPosition) {
						mHoldPosition = mLastPosition + 1;
						isSameDragDirection = !isSameDragDirection;
					} else {
						mHoldPosition = mLastPosition;
					}
				}

				xAbsOffset = 0;
				yAbsOffset = -mItemVerticalSpacing;
				mLastPosition++;

			} else {// 向上拖動

				if (lastFlag == -1) {
					lastFlag = 1;
					isSameDragDirection = true;
				}

				if (lastFlag == 0) {
					turnDownPosition = tempPosition;
					lastFlag = 1;
					isSameDragDirection = !isSameDragDirection;
				}

				if (isSameDragDirection) {
					mHoldPosition = mLastPosition - 1;
				} else {

					if (mStartPosition > tempPosition) {
						mHoldPosition = mLastPosition - 1;
						isSameDragDirection = !isSameDragDirection;
					} else {
						mHoldPosition = mLastPosition;
					}

				}

				xAbsOffset = 0;
				yAbsOffset = mItemVerticalSpacing;
				mLastPosition--;

			}

			adapter.setHeight(mItemVerticalSpacing);
			adapter.setIsSameDragDirection(isSameDragDirection);
			adapter.setLastFlag(lastFlag);

			ViewGroup moveView = (ViewGroup) getChildAt(mHoldPosition
					- getFirstVisiblePosition());

			Animation animation;
			if (isSameDragDirection) {// 相同方向拖動
				animation = getFromSelfAnimation(xAbsOffset, yAbsOffset);
			} else {// 不相同方向拖動
				animation = getToSelfAnimation(xAbsOffset, -yAbsOffset);
			}
			// 啟用對應的動畫
			moveView.startAnimation(animation);

		}
	}

	private void onDrop(int x, int y) {
		final DragListAdapter adapter = (DragListAdapter) getAdapter();
		adapter.setInvisiblePosition(-1);
		adapter.showDropItem(true);
		adapter.notifyDataSetChanged();
	}

	/**
	 * 準備拖動,初始化拖動項的影象
	 * 
	 * @param bm
	 * @param y
	 */
	private void startDrag(Bitmap bm, int y) {
		/***
		 * 初始化window.
		 */
		mWindowParams = new WindowManager.LayoutParams();
		mWindowParams.gravity = Gravity.TOP;
		mWindowParams.x = 0;
		mWindowParams.y = y - mDragPoint + mDragOffset;
		mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
		mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

		mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不需獲取焦點
				| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不需接受觸控事件
				| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 保持裝置常開,並保持亮度不變。
				| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;// 窗口占滿整個螢幕,忽略周圍的裝飾邊框(例如狀態列)。此視窗需考慮到裝飾邊框的內容。

		// windowParams.format = PixelFormat.TRANSLUCENT;// 預設為不透明,這裡設成透明效果.
		mWindowParams.windowAnimations = 0;// 視窗所使用的動畫設定

		mWindowParams.alpha = 0.8f;
		mWindowParams.format = PixelFormat.TRANSLUCENT;

		ImageView imageView = new ImageView(getContext());
		imageView.setImageBitmap(bm);

		mWindowManager.addView(imageView, mWindowParams);
		mDragImageView = imageView;
	}

	/**
	 * 拖動執行,在Move方法中執行
	 * 
	 * @param y
	 */
	public void onDrag(int y) {
		int drag_top = y - mDragPoint;// 拖拽view的top值不能<0,否則則出界.
		if (mDragImageView != null && drag_top >= 0) {
			mWindowParams.alpha = 1.0f;
			mWindowParams.y = y - mDragPoint + mDragOffset;
			mWindowManager.updateViewLayout(mDragImageView, mWindowParams);// 時時移動.
		}

		doScroller(y);// listview移動.
	}

	/***
	 * ListView的移動.
	 * 要明白移動原理:當我移動到下端的時候,ListView向上滑動,當我移動到上端的時候,ListView要向下滑動。正好和實際的相反.
	 * 
	 */
	public void doScroller(int y) {
		// ListView需要下滑
		if (y < mUpScrollBounce) {
			mCurrentStep = mStep + (mUpScrollBounce - y) / 10;// 時時步伐
		}// ListView需要上滑
		else if (y > mDownScrollBounce) {
			mCurrentStep = -(mStep + (y - mDownScrollBounce)) / 10;// 時時步伐
		} else {
			mCurrentStep = 0;
		}

		// 獲取你拖拽滑動到位置及顯示item相應的view上(注:可顯示部分)(position)
		View view = getChildAt(mDragPosition - getFirstVisiblePosition());
		// 真正滾動的方法setSelectionFromTop()
		setSelectionFromTop(mDragPosition, view.getTop() + mCurrentStep);

	}

	/**
	 * 停止拖動,刪除影像
	 */
	public void stopDrag() {
		isMoving = false;

		if (mDragImageView != null) {
			mWindowManager.removeView(mDragImageView);
			mDragImageView = null;
		}

		isSameDragDirection = true;
		lastFlag = -1;
		DragListAdapter adapter = (DragListAdapter) getAdapter();
		adapter.setLastFlag(lastFlag);
		adapter.pastList();
	}

	/**
	 * 拖動放下的時候
	 * 
	 * @param y
	 */
	public void onDrop(int y) {
		onDrop(0, y);
	}

	/**
	 * 獲取自身出現的動畫
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	private Animation getFromSelfAnimation(int x, int y) {
		TranslateAnimation translateAnimation = new TranslateAnimation(
				Animation.RELATIVE_TO_SELF, 0, Animation.ABSOLUTE, x,
				Animation.RELATIVE_TO_SELF, 0, Animation.ABSOLUTE, y);
		translateAnimation
				.setInterpolator(new AccelerateDecelerateInterpolator());
		translateAnimation.setFillAfter(true);
		translateAnimation.setDuration(ANIMATION_DURATION);
		translateAnimation.setInterpolator(new AccelerateInterpolator());
		return translateAnimation;
	}

	/**
	 * 獲取自身離開的動畫
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	private Animation getToSelfAnimation(int x, int y) {
		TranslateAnimation translateAnimation = new TranslateAnimation(
				Animation.ABSOLUTE, x, Animation.RELATIVE_TO_SELF, 0,
				Animation.ABSOLUTE, y, Animation.RELATIVE_TO_SELF, 0);
		translateAnimation
				.setInterpolator(new AccelerateDecelerateInterpolator());
		translateAnimation.setFillAfter(true);
		translateAnimation.setDuration(ANIMATION_DURATION);
		translateAnimation.setInterpolator(new AccelerateInterpolator());
		return translateAnimation;
	}

}

然後說下介面卡,程式碼如下
package com.pengguichu.testdraglistview.adapter;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.pengguichu.testdraglistview.R;

/**
 * 自定義可拖拽ListView介面卡
 * @author guichupeng 下午1:15:31
 */
public class DragListAdapter extends BaseAdapter {
	private List<String> mDataList;// 標題陣列
	private Context mContext;

	/**
	 * DragListAdapter構造方法
	 * 
	 * @param context
	 *            // 上下文物件
	 * @param dataList
	 *            // 資料集合
	 */
	public DragListAdapter(Context context, ArrayList<String> dataList) {
		this.mContext = context;
		this.mDataList = dataList;
	}

	/**
	 * 設定是否顯示下降的Item
	 * 
	 * @param showItem
	 */
	public void showDropItem(boolean showItem) {
		this.mShowItem = showItem;
	}

	/**
	 * 設定不可見項的位置標記
	 * 
	 * @param position
	 */
	public void setInvisiblePosition(int position) {
		mInvisilePosition = position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		/***
		 * 在這裡儘可能每次都進行例項化新的,這樣在拖拽ListView的時候不會出現錯亂.
		 * 具體原因不明,不過這樣經過測試,目前沒有發現錯亂。雖說效率不高,但是做拖拽LisView足夠了。
		 */
		convertView = LayoutInflater.from(mContext).inflate(
				R.layout.drag_list_item, null);

		initItemView(position, convertView);

		TextView titleTv = (TextView) convertView
				.findViewById(R.id.drag_item_title_tv);
		titleTv.setText(mDataList.get(position));

		if (isChanged) {// 判斷是否發生了改變

			if (position == mInvisilePosition) {

				if (!mShowItem) {// 在拖拽過程不允許顯示的狀態下,設定Item內容隱藏

					// 因為item背景為白色,故而在這裡要設定為全透明色防止有白色遮擋問題(向上拖拽)
					convertView.findViewById(R.id.drag_item_layout)
							.setBackgroundColor(0x0000000000);

					// 隱藏Item上面的內容
					int vis = View.INVISIBLE;
					convertView.findViewById(R.id.drag_item_image)
							.setVisibility(vis);
					convertView.findViewById(R.id.drag_item_close_layout)
							.setVisibility(vis);
					titleTv.setVisibility(vis);

				}

			}

			if (mLastFlag != -1) {

				if (mLastFlag == 1) {

					if (position > mInvisilePosition) {
						Animation animation;
						animation = getFromSelfAnimation(0, -mHeight);
						convertView.startAnimation(animation);
					}

				} else if (mLastFlag == 0) {

					if (position < mInvisilePosition) {
						Animation animation;
						animation = getFromSelfAnimation(0, mHeight);
						convertView.startAnimation(animation);
					}

				}

			}
		}

		return convertView;
	}

	/**
	 * 
	 * 初始化Item檢視
	 * 
	 * @param convertView
	 */
	private void initItemView(final int position, final View convertView) {

		if (convertView != null) {
			// 設定對應的監聽
			convertView.findViewById(R.id.drag_item_close_layout)
					.setOnClickListener(new OnClickListener() {// 刪除

								@Override
								public void onClick(View v) {
									// TODO Auto-generated method stub
									removeItem(position);
								}
							});
		}

	}

	private int mInvisilePosition = -1;// 用來標記不可見Item的位置
	private boolean isChanged = true;// 標識是否發生改變
	private boolean mShowItem = false;// 標識是否顯示拖拽Item的內容

	/***
	 * 動態修改ListView的方位.
	 * 
	 * @param startPosition
	 *            點選移動的position
	 * @param endPosition
	 *            鬆開時候的position
	 */
	public void exchange(int startPosition, int endPosition) {
		Object startObject = getItem(startPosition);

		if (startPosition < endPosition) {
			mDataList.add(endPosition + 1, (String) startObject);
			mDataList.remove(startPosition);
		} else {
			mDataList.add(endPosition, (String) startObject);
			mDataList.remove(startPosition + 1);
		}

		isChanged = true;
	}

	/**
	 * 動態修改Item內容
	 * 
	 * @param startPosition
	 *            // 開始的位置
	 * @param endPosition
	 *            // 當前停留的位置
	 */
	public void exchangeCopy(int startPosition, int endPosition) {
		Object startObject = getCopyItem(startPosition);

		if (startPosition < endPosition) {// 向下移動
			mCopyList.add(endPosition + 1, (String) startObject);
			mCopyList.remove(startPosition);
		} else {// 向上拖動或者不動
			mCopyList.add(endPosition, (String) startObject);
			mCopyList.remove(startPosition + 1);
		}

		isChanged = true;
	}

	/**
	 * 刪除指定的Item
	 * 
	 * @param pos
	 *            // 要刪除的下標
	 */
	private void removeItem(int pos) {
		if (mDataList != null && mDataList.size() > pos) {
			mDataList.remove(pos);
			this.notifyDataSetChanged();
		}
	}

	/**
	 * 獲取映象(拖拽)Item項
	 * 
	 * @param position
	 * @return
	 */
	public Object getCopyItem(int position) {
		return mCopyList.get(position);
	}

	/**
	 * 獲取Item總數
	 */
	@Override
	public int getCount() {
		return mDataList.size();
	}

	/**
	 * 獲取ListView中Item項
	 */
	@Override
	public Object getItem(int position) {
		return mDataList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	/**
	 * 新增拖動項
	 * 
	 * @param start
	 *            // 要進行新增的位置
	 * @param obj
	 */
	public void addDragItem(int start, Object obj) {
		mDataList.remove(start);// 刪除該項
		mDataList.add(start, (String) obj);// 新增刪除項
	}

	private ArrayList<String> mCopyList = new ArrayList<String>();

	public void copyList() {
		mCopyList.clear();
		for (String str : mDataList) {
			mCopyList.add(str);
		}
	}

	public void pastList() {
		mDataList.clear();
		for (String str : mCopyList) {
			mDataList.add(str);
		}
	}

	private boolean isSameDragDirection = true;// 是否為相同方向拖動的標記
	private int mLastFlag = -1;
	private int mHeight;
	private int mDragPosition = -1;

	/**
	 * 設定是否為相同方向拖動的標記
	 * 
	 * @param value
	 */
	public void setIsSameDragDirection(boolean value) {
		isSameDragDirection = value;
	}

	/**
	 * 設定拖動方向標記
	 * 
	 * @param flag
	 */
	public void setLastFlag(int flag) {
		mLastFlag = flag;
	}

	/**
	 * 設定高度
	 * 
	 * @param value
	 */
	public void setHeight(int value) {
		mHeight = value;
	}

	/**
	 * 設定當前拖動位置
	 * 
	 * @param position
	 */
	public void setCurrentDragPosition(int position) {
		mDragPosition = position;
	}

	/**
	 * 從自身出現的動畫
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	private Animation getFromSelfAnimation(int x, int y) {
		TranslateAnimation translateAnimation = new TranslateAnimation(
				Animation.RELATIVE_TO_SELF, 0, Animation.ABSOLUTE, x,
				Animation.RELATIVE_TO_SELF, 0, Animation.ABSOLUTE, y);
		translateAnimation
				.setInterpolator(new AccelerateDecelerateInterpolator());
		translateAnimation.setFillAfter(true);
		translateAnimation.setDuration(100);
		translateAnimation.setInterpolator(new AccelerateInterpolator());
		return translateAnimation;
	}
}
方法註釋很詳細,大家應該能弄明白,不行的話留言討論或者原始碼下載連線自己研究,展示圖如下