Android可长按拖拽item的列表
仿支付宝拖拽效果,长按拖拽item列表,自动换位
一、思路:
自定义控件DragGridView
二、效果图:
看视频更直观点:
Android轮子-可长按拖拽item的列表
三、关键代码:
package com.cong.mydraglistapp.drag;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import com.cong.mydraglistapp.R;
import java.util.ArrayList;
import java.util.List;
import static android.widget.AdapterView.INVALID_POSITION;
public class DragGridView extends GridViewForScrollView {
private static final int MOVE_DURATION = 300;
private static final int SCROLL_SPEED = 60;
private static final int EXTEND_LENGTH = 20;
private Vibrator vibrator;
private int lastX = -1;
private int lastY = -1;
/**
* 拖动时的图像 和 它的位置
*/
private BitmapDrawable hoverCell;
private Rect currentRect;
/**
* 要拖动的view
*/
private View selectView;
private int originPosition = INVALID_POSITION;
private int currentPosition = INVALID_POSITION;
private boolean isEdit;
public static boolean isDrag;
private boolean isSwap;
private List<Integer> noChangePositions = new ArrayList<>();
Paint localPaint;//画笔
Paint topPaint;//画笔
private DragCallback dragCallback;
public DragGridView(Context context) {
this(context, null);
}
public DragGridView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
localPaint = new Paint();
localPaint.setStrokeWidth(1);
localPaint.setStyle(Paint.Style.STROKE);
localPaint.setColor(getContext().getResources().getColor(R.color.c_f2f2f7));//设置画笔的颜色
topPaint = new Paint();
topPaint.setStrokeWidth(2);
topPaint.setStyle(Paint.Style.STROKE);
topPaint.setColor(getContext().getResources().getColor(R.color.c_f2f2f7));//设置画笔的颜色
}
public DragAdapterInterface getInterface() {
return (DragAdapterInterface) getAdapter();
}
public void setDragCallback(DragCallback dragCallback) {
this.dragCallback = dragCallback;
}
@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);
if (hoverCell != null) {
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);
}
public void clicked(int position) {
if (isEdit) {
isEdit = false;
return;
}
// resumeView();
Log.i("drag", "点击 Item " + position);
}
public List<Integer> getNoChangePositions() {
return noChangePositions;
}
public void setNoChangePositions(List<Integer> noChangePositions) {
this.noChangePositions = noChangePositions;
}
private void resumeView() {
if (selectView != null) {
// selectView.findViewById(R.id.delete_img).setVisibility(INVISIBLE);
selectView.findViewById(R.id.item_container).setVisibility(VISIBLE);
selectView.findViewById(R.id.item_container).setBackgroundColor(Color.WHITE);
}
}
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"));
// if (selectView.findViewById(R.id.delete_img) != null) {
// 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);
}
}
}
private void swapItems(int x, int y) {
int endPosition = pointToPosition(x, y);
boolean canChange = true;
for (int i:noChangePositions){
if (endPosition == i){
canChange = false;
break;
}
}
if (endPosition != INVALID_POSITION && endPosition != currentPosition && canChange) {
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(getContext().getResources().getColor(R.color.c_f2f2f7));
//selectView.findViewById(R.id.delete_img).setVisibility(VISIBLE);
// 动画显示交换过程
animateSwap(endPosition);
}
}
private void animateSwap(int endPosition) {
List<Animator> animators = new ArrayList<>();
if (endPosition < currentPosition) {
for (int i = endPosition + 1; i <= currentPosition; i++) {
View view = getChildAt(i - getFirstVisiblePosition());
if (i % getNumColumns() == 0) {
animators.add(createTranslationAnimations(view, view.getWidth() * (getNumColumns() - 1), 0,
-view.getHeight(), 0));
} else {
animators.add(createTranslationAnimations(view, -view.getWidth(), 0, 0, 0));
}
}
} else {
for (int i = currentPosition; i < endPosition; i++) {
View view = getChildAt(i - getFirstVisiblePosition());
if ((i + 1) % getNumColumns() == 0) {
animators.add(createTranslationAnimations(view, -view.getWidth() * (getNumColumns() - 1), 0,
view.getHeight(), 0));
} else {
animators.add(createTranslationAnimations(view, view.getWidth(), 0, 0, 0));
}
}
}
currentPosition = endPosition;
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animators);
animatorSet.setDuration(MOVE_DURATION);
animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
isSwap = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animatorSet.start();
}
private Animator createTranslationAnimations(View view, float startX, float endX, float startY, float endY) {
ObjectAnimator animX = ObjectAnimator.ofFloat(view, "translationX", startX, endX);
ObjectAnimator animY = ObjectAnimator.ofFloat(view, "translationY", startY, endY);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
return animSetXY;
}
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();
}
private BitmapDrawable getHoverCell(View view) {
int left = view.getLeft();
int top = view.getTop();
int w = view.getWidth();
int h = view.getHeight();
Bitmap bitmap = getBitmapFromView(view);
BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap);
currentRect = new Rect(left - EXTEND_LENGTH, top - EXTEND_LENGTH, left + w + EXTEND_LENGTH,
top + h + EXTEND_LENGTH);
drawable.setBounds(currentRect);
return drawable;
}
private Bitmap getBitmapFromView(View v) {
Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.draw(canvas);
return bitmap;
}
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);
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (hoverCell != null) {
hoverCell.draw(canvas);
}
// View localView1 = getChildAt(0);
// int column = getWidth() / localView1.getWidth();//计算出一共有多少列,假设有3列
// int childCount = getChildCount();//子view的总数
// System.out.println("子view的总数childCount==" + childCount);
//
// for (int i = 0; i < childCount; i++) {//遍历子view
// View cellView = getChildAt(i);//获取子view
// if (i < 4) {//第一行
// canvas.drawLine(cellView.getLeft(), cellView.getTop(), cellView.getRight(), cellView.getTop(), topPaint);
// }
// if (i % column == 0) {//第一列
// canvas.drawLine(cellView.getLeft(), cellView.getTop(), cellView.getLeft(), cellView.getBottom(), localPaint);
// }
// if ((i + 1) % column == 0) {//第三列
// //画子view底部横线
// canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
// canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
// } else if ((i + 1) > (childCount - (childCount % column))) {//如果view是最后一行
// //画子view的右边竖线
// canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
// canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
// } else {//如果view不是最后一行
// //画子view的右边竖线
// canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
// //画子view的底部横线
// canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
// }
// }
}
// @Override
// public boolean onInterceptTouchEvent(MotionEvent ev) {
// // TODO Auto-generated method stub
// if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// if (isDrag) {
// return false;
// } else {
// }
// }
// return super.onInterceptTouchEvent(ev);
// }
}
package com.cong.mydraglistapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import com.cong.mydraglistapp.drag.DragGridView;
import com.cong.mydraglistapp.drag.MyDragAdapter;
import java.util.ArrayList;
import java.util.List;
public class CatalogSortActivity extends AppCompatActivity {
private DragGridView dragGridView;
private MyDragAdapter adapterSelect;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catalog_sort);
dragGridView = findViewById(R.id.dgv_catalog);
//模拟添加数据
List<String> datas = new ArrayList<>();
datas.add("A");
datas.add("B");
datas.add("C");
datas.add("D");
datas.add("E");
datas.add("F");
datas.add("G");
datas.add("H");
datas.add("I");
datas.add("J");
datas.add("K");
datas.add("L");
datas.add("N");
datas.add("M");
datas.add("O");
datas.add("P");
adapterSelect = new MyDragAdapter(this,datas);
dragGridView.setAdapter(adapterSelect);
dragGridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (!dragGridView.getNoChangePositions().contains(position)){
dragGridView.startDrag(position);
}
return false;
}
});
}
}
四、项目demo源码效果图:
有问题或者需要完整demo源码的私信我,我每天都看私信的