RecyclerView長按拖拽排序 ,縮短長按響應時間,長按0.1秒就可以開始拖動
度娘搜索RecyclerView長按拖拽排序,很多文章講解,沒找到縮短長按響應時間的,所以自己研究了一下
本文借鑑其他博客實現基本的拖拽排序功能,修改長按響應時間是自己實現的,轉載請註明原文鏈接
先看效果圖
上代碼(核心代碼 重寫itemtouchhelper)
代碼有註釋,有問題可以評論回覆,儘量及時答覆
package com.example.itemtouchhelper;
import android.app.Service;
import android.graphics.Color;
import android.os.Handler;
import android.os.Vibrator;
import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.Collections;
import java.util.List;
/**
* @author FANG SHIXIAN
* @date 2020/6/23.
* description:
*/
public class MyItemTouchHelper {
/**
* 已選圖片拖動改變順序,
* 禁止添加圖片的item拖拽,
* 拖拽到添加圖片的位置不響應位置交換
*/
public static <T> void initItemTouchHelper(final RecyclerView recycler, final RecyclerView.Adapter adapter, final List<T> list) {
ItemTouchHelper helper;
ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
//某個類型的viewHolder不可拖動
// if (viewHolder instanceof XXViewHolder){ // XXViewHolder 是不可拖動的viewHolder類型,使用的時候替換
// return makeMovementFlags(0,0);
// }
int dragFlag = 0;
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
//GridLayout佈局允許 上下左右 拖動
dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
} else if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
//LinearLayout佈局 只允許 上下 拖動
dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
}
//dier個參數swipeFlags應該是拖動刪除
return makeMovementFlags(dragFlag, 0);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//滑動事件 下面註釋的代碼,滑動後數據和條目錯亂,被捨棄
// Collections.swap(datas,viewHolder.getAdapterPosition(),target.getAdapterPosition());
// ap.notifyItemMoved(viewHolder.getAdapterPosition(),target.getAdapterPosition());
//得到當拖拽的viewHolder的Position
int fromPosition = viewHolder.getAdapterPosition();
//拿到當前拖拽到的item的viewHolder
int toPosition = target.getAdapterPosition();
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(list, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(list, i, i - 1);
}
}
adapter.notifyItemMoved(fromPosition, toPosition);
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//側滑刪除可以使用;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* 長按選中Item的時候開始調用
* 長按高亮
* @param viewHolder
* @param actionState
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setBackgroundColor(Color.RED);//(拖動開始 修改item的背景色,我這裏設置了紅色)
//獲取系統震動服務//震動70毫秒 (需要添加震動權限)
Vibrator vib = (Vibrator) recycler.getContext().getSystemService(Service.VIBRATOR_SERVICE);
vib.vibrate(70);
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 手指鬆開的時候還原高亮
* @param recyclerView
* @param viewHolder
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setBackgroundColor(Color.BLUE);//(拖動結束後恢復item的背景色,我這裏故意設置了藍色)
// adapter.notifyDataSetChanged(); //完成拖動後刷新適配器,這樣拖動後刪除就不會錯亂(拖動排序不是必須的)
}
};
helper = new ItemTouchHelper(callback);
helper.attachToRecyclerView(recycler);//ItemTouchHelper綁定recyclerView
// ItemTouchHelperGestureListener原生不是public修飾的,需要把源碼複製到項目裏才能實例化
ItemTouchHelper.ItemTouchHelperGestureListener listener = helper.getmItemTouchHelperGestureListener();
//Handler最後是全局使用同一個,避免內存泄漏,
// 我這裏demo爲了方便直接new Handler()
setLongClickDelay(new Handler(), recycler, 100, listener);
}
/**
* 修改item長按拖動的響應時間
* @param handler Handler
* @param v RecyclerView
* @param delay 長按響應時間
* @param itemTouchHelperGestureListener 修改源碼後的ItemTouChHelper的itemTouchHelperGestureListener
*/
private static void setLongClickDelay(final Handler handler, final RecyclerView v, long delay,
final ItemTouchHelper.ItemTouchHelperGestureListener itemTouchHelperGestureListener) {
final long delayMillis = delay < 50 ? 50 : delay;
v.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
private static final int TOUCH_MAX = 50;
MotionEvent mEvent;
private int mLastMotionX;
private int mLastMotionY;
private boolean mHasPerformedLongPress = false;
private Runnable performLongClick = new Runnable() {
@Override
public void run() {
// mHasPerformedLongPress = v.performLongClick();
if (mEvent != null) {
mHasPerformedLongPress = true;
//響應長按onLongPress
itemTouchHelperGestureListener.onLongPress(mEvent);
mEvent = null;
}
}
};
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
mEvent = null;
handler.removeCallbacks(performLongClick);
// case 1
v.setTag(mHasPerformedLongPress);
v.performClick();
// case 2
/*if (!mHasPerformedLongPress) {
v.performClick();
}*/
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(mLastMotionX - x) > TOUCH_MAX || Math.abs(mLastMotionY - y) > TOUCH_MAX) {
mEvent = null;
handler.removeCallbacks(performLongClick);
}
break;
case MotionEvent.ACTION_DOWN:
mHasPerformedLongPress = false;
handler.removeCallbacks(performLongClick);
mLastMotionX = x;
mLastMotionY = y;
// 不能直接用mEvent = event,這樣賦值 mEvent 的 getX 和 getY 得到的值是相對屏幕(或者是父佈局)的,
// 具體原理不清楚
mEvent = MotionEvent.obtain(event);
handler.postDelayed(performLongClick, delayMillis);
break;
case MotionEvent.ACTION_CANCEL:
handler.removeCallbacks(performLongClick);
break;
}
return false;
}
@Override
public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent event) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
// v.setOnTouchListener(new View.OnTouchListener() {
// private static final int TOUCH_MAX = 50;
//
// private int mLastMotionX;
// private int mLastMotionY;
// private boolean mHasPerformedLongPress = false;
//
// private Runnable performLongClick = new Runnable() {
// @Override
// public void run() {
// mHasPerformedLongPress = v.performLongClick();
// }
// };
//
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// int x = (int) event.getX();
// int y = (int) event.getY();
//
// switch (event.getAction()) {
// case MotionEvent.ACTION_UP:
// handler.removeCallbacks(performLongClick);
// // case 1
// v.setTag(mHasPerformedLongPress);
// v.performClick();
// // case 2
// /*if (!mHasPerformedLongPress) {
// v.performClick();
// }*/
// break;
// case MotionEvent.ACTION_MOVE:
// if (Math.abs(mLastMotionX - x) > TOUCH_MAX || Math.abs(mLastMotionY - y) > TOUCH_MAX) {
// handler.removeCallbacks(performLongClick);
// }
// break;
// case MotionEvent.ACTION_DOWN:
// time = System.currentTimeMillis();
// Log.e("test", time + " ACTION_DOWN ");
//
// mHasPerformedLongPress = false;
// handler.removeCallbacks(performLongClick);
// mLastMotionX = x;
// mLastMotionY = y;
// handler.postDelayed(performLongClick, delayMillis);
// break;
// }
// return false;
// }
// });
}
}