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;
//            }
//        });
    }
}


最後上源碼地址 ItemTouchHelper 縮短長按響應時間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章