参考了github上一个dynamicgrid
源代码地址 https://github.com/aspros523/DragGridView
思路
1.长按的时候触发拖动
获取所选择的item的图像,稍微放大并随手指移动。
显示图像用一个BitmapDrawable 移动的时候设置它的bounds,并调用invalidate函数重绘。
public void startDrag(int position)
{
if (position == INVALID_POSITION)
{
return;
}
//恢复之前的图像,改变背景,去除删除按钮
resumeView();
selectView = getChildAt(position - getFirstVisiblePosition());
if (selectView != null)
{
isDrag = true;
isEdit = true;
/**
* 移动的图像背景要有区别,并显示删除按钮
*/
selectView.findViewById(R.id.item_container).setBackgroundColor(Color.parseColor("#f0f0f0"));
selectView.findViewById(R.id.delete_img).setVisibility(VISIBLE);
originPosition = position;
currentPosition = position;
vibrator.vibrate(60);
//获取图像
hoverCell = getHoverCell(selectView);
selectView.findViewById(R.id.item_container).setVisibility(INVISIBLE);
if(dragCallback!=null)
{
dragCallback.startDrag(position);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev)
{
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
if (isDrag)
{
int offsetX = x - lastX;
int offsetY = y - lastY;
lastX = x;
lastY = y;
currentRect.offset(offsetX, offsetY);
hoverCell.setBounds(currentRect);
invalidate();
if (!isSwap)
{
swapItems(x, y);
}
handleScroll();
return false;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isDrag)
{
endDrag();
}
break;
default:
}
return super.onTouchEvent(ev);
}
2.移动时根据bounds的中点用pointToPosition函数获取在gridview中的位置,判断是否要交换内容。
如果和原来的位置不同,就交换内容,并用动画显示交换过程。
private void swapItems(int x, int y)
{
int endPosition = pointToPosition(x, y);
if (endPosition != INVALID_POSITION && endPosition != currentPosition)
{
isSwap = true;
isEdit = false;
resumeView();
//交换数据内容
getInterface().reOrder(currentPosition, endPosition);
selectView=getChildAt(endPosition-getFirstVisiblePosition());
selectView.findViewById(R.id.item_container).setVisibility(INVISIBLE);
selectView.findViewById(R.id.item_container).setBackgroundColor(Color.parseColor("#f0f0f0"));
selectView.findViewById(R.id.delete_img).setVisibility(VISIBLE);
//动画显示交换过程
animateSwap(endPosition);
}
}
3.放开后,用一个动画让图像回到原来位置
private void endDrag()
{
currentRect.set(selectView.getLeft(), selectView.getTop(), selectView.getRight(), selectView.getBottom());
animateBound();
}
private void animateBound()
{
TypeEvaluator<Rect> evaluator = new TypeEvaluator<Rect>()
{
@Override
public Rect evaluate(float fraction, Rect startValue, Rect endValue)
{
return new Rect(interpolate(startValue.left, endValue.left, fraction),
interpolate(startValue.top, endValue.top, fraction),
interpolate(startValue.right, endValue.right, fraction),
interpolate(startValue.bottom, endValue.bottom, fraction));
}
public int interpolate(int start, int end, float fraction)
{
return (int) (start + fraction * (end - start));
}
};
ObjectAnimator animator = ObjectAnimator.ofObject(hoverCell, "bounds", evaluator, currentRect);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
invalidate();
}
});
animator.addListener(new Animator.AnimatorListener()
{
@Override
public void onAnimationStart(Animator animation)
{
}
@Override
public void onAnimationEnd(Animator animation)
{
isDrag = false;
if (currentPosition != originPosition)
{
resumeView();
originPosition = currentPosition;
}
hoverCell = null;
selectView.findViewById(R.id.item_container).setVisibility(VISIBLE);
if (dragCallback != null)
{
dragCallback.endDrag(currentPosition);
}
}
@Override
public void onAnimationCancel(Animator animation)
{
}
@Override
public void onAnimationRepeat(Animator animation)
{
}
});
animator.start();
}
4 拖动到顶部或者底部时自动滚动
private void handleScroll()
{
int offset=computeVerticalScrollOffset();
int height=getHeight();
int extent=computeVerticalScrollExtent();
int range=computeHorizontalScrollRange();
if(currentRect.top<=0 && offset>0)
{
smoothScrollBy(-SCROLL_SPEED,0);
}
else
if(currentRect.bottom>=height && (offset+extent)<range)
{
smoothScrollBy(SCROLL_SPEED,0);
}
}