可拖动重排GridView

先上效果图(动态图不会做,见谅):


控件功能特色:

1、长按item可以拖动重排

2、可以自定义重排的方式

3、被移动位置和将要移动到的位置有图形显示

这个控件前身来自于Github,针对其做了以下改进:

1、修复了被拖动的View到边缘会消失的bug

2、修复有时候数据没有重排的bug

3、增加了被移动位置和将要移动到的位置有图形显示的功能

Demo下载地址:

http://download.csdn.net/detail/cmeiyuan/6823213


附源码:

package com.cmeiyuan.dragsortgridviewdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.DragEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ListAdapter;

import com.cmeiyuan.dragsortgridviewdemo.ReorderArray.onMoveListener;

public class DragSortGridView extends GridView implements onMoveListener {

	private static final boolean DEBUG = true;
	private static final String TAG = "DragSortGridView";
	private static final SparseArray<String> DRAG_EVENT_ACTION;

	static {
		if (DEBUG) {
			DRAG_EVENT_ACTION = new SparseArray<String>();
			DRAG_EVENT_ACTION.put(DragEvent.ACTION_DRAG_STARTED,
					"ACTION_DRAG_STARTED");
			DRAG_EVENT_ACTION.put(DragEvent.ACTION_DRAG_ENTERED,
					"ACTION_DRAG_ENTERED");
			DRAG_EVENT_ACTION.put(DragEvent.ACTION_DRAG_LOCATION,
					"ACTION_DRAG_LOCATION");
			DRAG_EVENT_ACTION.put(DragEvent.ACTION_DRAG_EXITED,
					"ACTION_DRAG_EXITED");
			DRAG_EVENT_ACTION.put(DragEvent.ACTION_DRAG_ENDED,
					"ACTION_DRAG_ENDED");
			DRAG_EVENT_ACTION.put(DragEvent.ACTION_DROP, "ACTION_DROP");
		}
	}

	private static final int FLAG_DRAW_APPEARING = 0x1;
	private static final int FLAG_DRAW_DISAPPEARING = 0x2;

	private boolean mDragSortEnabled;

	private int mLastDragPosition;
	private int mLastTargetPosition;
	private int mAppearingPosition;
	private int mDisappearingPosition;
	private int mMovingChildViewsNum;
	private int mPrivateFlags;

	private Drawable mAppearingDrawable;
	private Drawable mDisappearingDrawable;
	private Animation mFadeOutAnimation;
	private ReorderArray mReorderArray;
	private Handler mHandler = new Handler();
	private OnReorderContentListener mOnReorderListener;

	public DragSortGridView(Context context) {
		super(context);
		init(context);
	}

	public DragSortGridView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public DragSortGridView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	private final void init(Context context) {

		mDragSortEnabled = true;

		mFadeOutAnimation = new AlphaAnimation(1.0f, 0.0f);
		mFadeOutAnimation.setDuration(150);
		mFadeOutAnimation.setFillEnabled(true);
		mFadeOutAnimation.setFillAfter(true);
		mFadeOutAnimation.setInterpolator(new AccelerateInterpolator());

		setOnItemLongClickListener(new OnItemLongClickListener() {

			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view,
					int position, long id) {
				if (mDragSortEnabled) {
					view.startDrag(null, new View.DragShadowBuilder(view),
							position, 0);
					return true;
				}
				return false;
			}

		});

		setOnDragListener(new OnDragListener() {

			@Override
			public boolean onDrag(View v, DragEvent event) {

				final int x = Math.round(event.getX());
				final int y = Math.round(event.getY());

				final int action = event.getAction();

				if (DEBUG) {
					Log.d("adapter",
							"event action:" + DRAG_EVENT_ACTION.get(action)
									+ "---------x:" + x + "y:" + y);
				}

				ListAdapter adapter = getAdapter();

				switch (action) {
				case DragEvent.ACTION_DRAG_STARTED:

					if (adapter instanceof DragSortAdapter) {
						DragSortAdapter dragSortAdapter = (DragSortAdapter) adapter;
						mReorderArray = dragSortAdapter.getReorderArray();
					}

					if (mReorderArray == null) {
						mReorderArray = new ReorderArray(adapter.getCount());
					}

					mReorderArray.setOnMoveListener(DragSortGridView.this);

					int actualPos = (Integer) event.getLocalState();
					View dragView = getView(actualPos);
					dragView.startAnimation(mFadeOutAnimation);

					mPrivateFlags |= FLAG_DRAW_DISAPPEARING;

					mLastDragPosition = actualPos;
					mDisappearingPosition = actualPos;
					mLastTargetPosition = -1;

					break;
				case DragEvent.ACTION_DRAG_ENTERED:
					break;
				case DragEvent.ACTION_DRAG_LOCATION:

					if (mMovingChildViewsNum > 0) {
						break;
					}

					// 得到的是原始位置
					int originalPos = getOriginalPos(x, y);
					// 目标实际位置
					int targetPos = originalPos == -1 ? -1 : mReorderArray
							.indexOf(originalPos);

					if (-1 != targetPos && targetPos != mLastTargetPosition) {

						if (DEBUG) {
							Log.d(TAG, "targetPos:" + targetPos);
						}

						// 如果目标位置和拖动位置相同,则不在目标显示Appearing
						if (targetPos != mLastDragPosition) {
							mPrivateFlags &= ~FLAG_DRAW_DISAPPEARING;
							mPrivateFlags |= FLAG_DRAW_APPEARING;
							mAppearingPosition = targetPos;
						}

						mLastTargetPosition = targetPos;

						int dragPositon = mLastDragPosition;

						reOrderViews(dragPositon, targetPos);

						mLastDragPosition = targetPos;

					}

					break;
				case DragEvent.ACTION_DRAG_EXITED:
					break;
				case DragEvent.ACTION_DRAG_ENDED:

					int fromPos = mReorderArray.get(mLastTargetPosition);
					int toPos = mLastTargetPosition;

					int dragViewPos = toPos == -1 ? mLastDragPosition : toPos;

					View lastDragView = getView(dragViewPos);
					lastDragView.clearAnimation();

					NotifyExecutor executor = new NotifyExecutor(fromPos, toPos);
					mHandler.post(executor);

					mLastDragPosition = -1;
					mLastTargetPosition = -1;
					break;
				case DragEvent.ACTION_DROP:

					break;
				}

				return true;
			}
		});

	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		Log.d(TAG, "onDraw");

		if ((mPrivateFlags & FLAG_DRAW_APPEARING) != 0) {

			Drawable drawable = mAppearingDrawable;
			int position = mAppearingPosition;
			if (position != -1 && drawable != null) {

				drawIndicator(canvas, position, drawable);
			}
		} else if ((mPrivateFlags & FLAG_DRAW_DISAPPEARING) != 0) {
			Drawable drawable = mDisappearingDrawable;
			int position = mDisappearingPosition;
			if (position != -1 && drawable != null) {

				drawIndicator(canvas, position, drawable);
			}
		}
	}

	// 在position位置显示将要添加item的标志
	protected void showAppearingAtPosition(int position) {
		mPrivateFlags |= FLAG_DRAW_APPEARING;
		this.mAppearingPosition = position;
	}

	// 在position位置显示将要移除item的标志
	protected void showDisappearingAtPosition(int position) {
		mPrivateFlags |= FLAG_DRAW_DISAPPEARING;
		this.mDisappearingPosition = position;
	}

	protected void hideAppearing() {
		mPrivateFlags &= ~FLAG_DRAW_APPEARING;
	}

	protected void hideDisappearing() {
		mPrivateFlags &= ~FLAG_DRAW_DISAPPEARING;
	}

	public void setDragSortEnabled(boolean enabled) {
		this.mDragSortEnabled = enabled;
	}

	protected void drawIndicator(Canvas canvas, int position, Drawable drawable) {
		if (position == -1) {
			return;
		}
		View view = getView(position);
		if (view == null) {
			return;
		}
		canvas.save();
		int l = view.getLeft();
		int t = view.getTop();
		canvas.translate(l, t);
		drawable.setBounds(0, 0, view.getWidth(), view.getHeight());
		drawable.draw(canvas);
		canvas.restore();
	}

	// 在动画完成后发出顺序改变的通知
	private final void notifyAfterMoveView(int fromPos, int toPos) {

		if (-1 == toPos || fromPos == toPos) {
			return;
		}

		if (mOnReorderListener != null) {
			mOnReorderListener.onReOrderContent(fromPos, toPos);
		} else {
			ListAdapter adapter = getAdapter();
			if (adapter instanceof DragSortAdapter) {
				DragSortAdapter dragSortAdapter = (DragSortAdapter) adapter;
				dragSortAdapter.onReOrderContent(fromPos, toPos);
			}
		}
	}

	private class NotifyExecutor implements Runnable {

		private int mFromPos;
		private int mToPos;

		public NotifyExecutor(int fromPos, int toPos) {
			this.mFromPos = fromPos;
			this.mToPos = toPos;
		}

		@Override
		public void run() {

			if (mMovingChildViewsNum > 0) {
				mHandler.postDelayed(this, 200);
			} else {
				mPrivateFlags &= ~FLAG_DRAW_APPEARING;
				notifyAfterMoveView(mFromPos, mToPos);
			}
		}

	}

	private void reOrderViews(int fromPos, int toPos) {

		Log.d(TAG, "reOrder:" + fromPos + "<-->" + fromPos);

		if (fromPos == toPos) {
			return;
		}

		// 在移动View子前,取得拖动的View,以及目标位置
		final View fromView = getView(fromPos);
		final View toView = getView(toPos);
		final Rect toRect = new Rect();
		getRect(toView, toRect);

		mReorderArray.reOrder(fromPos, toPos);

		fromView.layout(toRect.left, toRect.top, toRect.right, toRect.bottom);

	}

	@Override
	public void onMove(int fromPos, int toPos) {

		if (DEBUG) {
			Log.d(TAG, fromPos + " move to " + toPos);
		}

		moveView(fromPos, toPos);

	}

	// 传入实际的都是实际位置
	private void moveView(int fromPos, int toPos) {

		final View fromView = getView(fromPos);
		final View toView = getView(toPos);

		final Rect fromRect = new Rect();
		final Rect toRect = new Rect();

		getRect(fromView, fromRect);
		getRect(toView, toRect);

		int tx = toRect.left - fromRect.left;
		int ty = toRect.top - fromRect.top;

		Animation translate = new TranslateAnimation(0, tx, 0, ty);

		translate.setDuration(150);
		translate.setFillEnabled(true);
		translate.setFillAfter(true);
		translate.setAnimationListener(new MoveViewAnimationListener(fromView,
				toView.getLeft(), toView.getTop()));

		fromView.startAnimation(translate);
		mMovingChildViewsNum++;
	}

	// 返回实际position的View对象
	protected View getView(int actualPos) {
		// 将实际position转换成原始position
		int originalPos = actualPos;
		ReorderArray array = mReorderArray;
		if (array != null) {
			originalPos = array.get(actualPos);
		}
		return getChildAt(originalPos - getFirstVisiblePosition());
	}

	protected void getRect(View view, Rect rect) {
		rect.set(view.getLeft(), view.getTop(), view.getRight(),
				view.getBottom());
	}

	// 返回坐标点View对象的原始位置
	private int getOriginalPos(int x, int y) {
		return pointToPosition(x, y);
	}

	public void setOnReorderedListener(OnReorderContentListener listener) {
		this.mOnReorderListener = listener;
	}

	public void setAppearingDrawable(int id) {
		mAppearingDrawable = getResources().getDrawable(id);
	}

	public void setDisappearingDrawable(int id) {
		mDisappearingDrawable = getResources().getDrawable(id);
	}

	protected Drawable getAppearingDrawable() {
		return mAppearingDrawable;
	}

	protected Drawable getDisappearingDrawable() {
		return mDisappearingDrawable;
	}

	public interface OnReorderContentListener {
		/**
		 * implement this to reorder your content data and call
		 * notifyDataSetChanged() in this function
		 */
		public void onReOrderContent(int fromPos, int toPos);
	}

	private class MoveViewAnimationListener implements
			Animation.AnimationListener {

		private View mTarget;
		private int mNewX, mNewY;

		public MoveViewAnimationListener(View target, int newX, int newY) {
			this.mTarget = target;
			this.mNewX = newX;
			this.mNewY = newY;
		}

		@Override
		public void onAnimationEnd(Animation animation) {
			mTarget.layout(mNewX, mNewY, mNewX + mTarget.getWidth(), mNewY
					+ mTarget.getHeight());
			mTarget.clearAnimation();
			mMovingChildViewsNum--;
		}

		@Override
		public void onAnimationRepeat(Animation animation) {

		}

		@Override
		public void onAnimationStart(Animation animation) {

		}

	}

}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值