RecyclerView<第四十二篇>:ItemTouchHelper詳解

ItemTouchHelper是RecyclerView高級(jí)篇的重要知識(shí)之一,它可以實(shí)現(xiàn)Item的拖拽以及側(cè)滑刪除。

先來(lái)看一下效果,如下:

365.gif

在了解效果的前提下,我將一步步剖析其實(shí)現(xiàn)原理。

(1)基本使用

我們首先需要了解,ItemTouchHelper如何使用,看以下代碼

    //聲明一個(gè)Callback
    ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {
        @Override
        public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            //返回方向值
            return 0;
        }

        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            //拖拽處理
            return false;
        }

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            //滑動(dòng)處理
        }
    };
    //創(chuàng)建helper對(duì)象
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
    //關(guān)聯(lián)recyclerView
    itemTouchHelper.attachToRecyclerView(recyclerview);

或者

    //聲明一個(gè)Callback
    ItemTouchHelper.Callback callback = new ItemTouchHelper.SimpleCallback(dragDirs, swipeDirs) {

        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            //拖拽處理
            return false;
        }

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            //滑動(dòng)處理
        }
    };
    //創(chuàng)建helper對(duì)象
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
    //關(guān)聯(lián)recyclerView
    itemTouchHelper.attachToRecyclerView(recyclerview);

attachToRecyclerView方法理解起來(lái)比較簡(jiǎn)單,就是將RecyclerView與ItemTouchHelper進(jìn)行關(guān)聯(lián),唯一不清楚的是,Callback中的三個(gè)方法沒(méi)有任何的業(yè)務(wù)邏輯,我們必須在這三個(gè)方法中處理這三個(gè)方法的業(yè)務(wù)邏輯,如果不處理,那么ItemTouchHelper則無(wú)任何效果。

在實(shí)現(xiàn)Callback內(nèi)部三個(gè)方法業(yè)務(wù)邏輯之前,我們需要了解這三個(gè)方法分別代表的意義:

  • getMovementFlags:移動(dòng)標(biāo)志;
  • onMove:拖拽的處理
  • onSwiped:滑動(dòng)的處理
(2)getMovementFlags: 獲取移動(dòng)狀態(tài)

ItemTouchHelper幫助類(lèi)自帶創(chuàng)建移動(dòng)標(biāo)志的方法,如下代碼:

    /**
     * Convenience method to create movement flags.
     * <p>
     * For instance, if you want to let your items be drag & dropped vertically and swiped
     * left to be dismissed, you can call this method with:
     * <code>makeMovementFlags(UP | DOWN, LEFT);</code>
     *
     * @param dragFlags  The directions in which the item can be dragged.
     * @param swipeFlags The directions in which the item can be swiped.
     * @return Returns an integer composed of the given drag and swipe flags.
     */
    public static int makeMovementFlags(int dragFlags, int swipeFlags) {
        return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags)
                | makeFlag(ACTION_STATE_SWIPE, swipeFlags)
                | makeFlag(ACTION_STATE_DRAG, dragFlags);
    }

dragFlags表示拖拽方向標(biāo)志,swipeFlags表示滑動(dòng)方向標(biāo)志,這個(gè)標(biāo)志可以理解為一種狀態(tài),那么這兩個(gè)值傳遞怎樣的參數(shù)呢?

    //控制拖拽的方向(一般是上下左右)
    int dragFlags= ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
    //控制快速滑動(dòng)的方向(一般是左右)
    int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;

我們看一下以上代碼,假設(shè):

dragFlags被賦予上下左右四個(gè)方向狀態(tài),所以拖拽方向狀態(tài)為:上、下、左、右
swipeFlags 被賦予左右兩個(gè)方向狀態(tài),所以滑動(dòng)方向狀態(tài)為:左、右

將拖拽方向狀態(tài)dragFlags以及滑動(dòng)方向狀態(tài)swipeFlags傳遞到makeMovementFlags方法中,接著看一下makeFlag這個(gè)方法:

    /**
     * Shifts the given direction flags to the offset of the given action state.
     *
     * @param actionState The action state you want to get flags in. Should be one of
     *                    {@link #ACTION_STATE_IDLE}, {@link #ACTION_STATE_SWIPE} or
     *                    {@link #ACTION_STATE_DRAG}.
     * @param directions  The direction flags. Can be composed from {@link #UP}, {@link #DOWN},
     *                    {@link #RIGHT}, {@link #LEFT} {@link #START} and {@link #END}.
     * @return And integer that represents the given directions in the provided actionState.
     */
    @SuppressWarnings("WeakerAccess")
    public static int makeFlag(int actionState, int directions) {
        return directions << (actionState * DIRECTION_FLAG_COUNT);
    }

這個(gè)方法最后的返回值為三種狀態(tài):無(wú)操作狀態(tài)、拖拽狀態(tài)、滑動(dòng)狀態(tài)(注意和拖拽方向狀態(tài)、滑動(dòng)方向狀態(tài)區(qū)別開(kāi)),最終makeMovementFlags的返回值為:

    return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags)
            | makeFlag(ACTION_STATE_SWIPE, swipeFlags)
            | makeFlag(ACTION_STATE_DRAG, dragFlags);

將無(wú)操作狀態(tài)、滑動(dòng)狀態(tài)、拖拽狀態(tài)合并為移動(dòng)狀態(tài)

以上所述的狀態(tài)優(yōu)點(diǎn)多,您可能會(huì)被繞暈,所以專(zhuān)門(mén)為大家繪制了一個(gè)思維導(dǎo)圖:

圖片.png

如圖所示,起初通過(guò)上下左右這四個(gè)方向狀態(tài),一步一步的轉(zhuǎn)變?yōu)橐苿?dòng)狀態(tài)。

如果您使用SimpleCallback內(nèi)部類(lèi),在內(nèi)部有一個(gè)方法如下:

    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView,
            @NonNull ViewHolder viewHolder) {
        return makeMovementFlags(getDragDirs(recyclerView, viewHolder),
                getSwipeDirs(recyclerView, viewHolder));
    }

這個(gè)方法表明,使用SimpleCallback內(nèi)部類(lèi)不需要重寫(xiě)getMovementFlags方法,只需要傳遞dragDirs, swipeDirs這兩個(gè)參數(shù)即可,其實(shí)和Callback內(nèi)部類(lèi)差不多,如果使用Callback內(nèi)部類(lèi),那么getMovementFlags完善后的代碼如下:

    //聲明一個(gè)Callback
    ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {

        @Override
        public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            //控制拖拽的方向(一般是上下左右)
            int dragFlags= ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            //控制快速滑動(dòng)的方向(一般是左右)
            int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            return makeMovementFlags(dragFlags, swipeFlags);//計(jì)算movement flag值
        }

        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            //拖拽處理
            return false;
        }

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            //滑動(dòng)處理
        }
    };

就這樣,getMovementFlags方法已經(jīng)實(shí)現(xiàn)完成,代碼的意思是:在拖拽時(shí),允許Item上、下、左、右四個(gè)方向拖拽,在滑動(dòng)時(shí),允許Item左、右兩個(gè)方向滑動(dòng)。

當(dāng)然,如果您只想讓Item向左滑動(dòng),那么將以下代碼

        int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;

改成

       int swipeFlags = ItemTouchHelper.LEFT;

或者

            //控制快速滑動(dòng)的方向(一般是左右)
            int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            //排除右方向
            swipeFlags &=~ItemTouchHelper.RIGHT;

即可。

有關(guān)添加狀態(tài)移除狀態(tài)相關(guān)算法我補(bǔ)充一下吧,雖然不是文章的重點(diǎn)(其實(shí),我怕您看不懂)

  • 使用按位或添加狀態(tài),如:
 flag |= ItemTouchHelper.RIGHT
  • 使用按位與和按位非移除狀態(tài),如:
flag &= ~ItemTouchHelper.RIGHT
(3)onMove: 拖拽處理

方法如下:

        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            //拖拽處理

            return true;
        }

這個(gè)方法是有返回值的,true:允許拖拽 false:禁止拖拽

假設(shè),有一個(gè)需求,將Item拖拽到某個(gè)位置,并和當(dāng)前位置的Item交換位置,這個(gè)該怎么做呢?

這個(gè)需求的處理,可以在onMove方法中處理,因?yàn)樗娜齻€(gè)參數(shù)recyclerView、viewHolder、target為這個(gè)需求提供了一切前提,viewHolder是被拖拽的Item,target是目標(biāo)Item,只需要將viewHolder和target交換位置就可以實(shí)現(xiàn)這個(gè)需求,代碼實(shí)現(xiàn)也比較簡(jiǎn)單,如下:

        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            // 拖拽時(shí),每移動(dòng)一個(gè)位置就會(huì)調(diào)用一次。

            if (recyclerView == null){
                return false;
            }

            RecyclerView.Adapter adapter = recyclerView.getAdapter();
            if (adapter == null){
                return false;
            }

            if (list != null && list.size() > 0) {
                //獲取被拖拽的Item的Position
                int from = viewHolder.getAdapterPosition();
                //獲取目標(biāo)Item的Position
                int endPosition = target.getAdapterPosition();
                //交換List集合中兩個(gè)元素的位置
                Collections.swap(list, from, endPosition);
                //交換界面上兩個(gè)Item的位置
                adapter.notifyItemMoved(from, endPosition);
            }
            return true;
        }

效果如下:

359.gif
(4)onSwiped: 滑動(dòng)處理

onSwiped是為了實(shí)現(xiàn)Item的左右滑動(dòng),由于我在getMovementFlags方法中已經(jīng)允許讓Item左右側(cè)滑,所以此時(shí)Item是只吃左右滑動(dòng)的,效果如下:

360.gif

如圖所示,在界面刪Item已經(jīng)被刪除,但是,您知道的,List數(shù)據(jù)對(duì)應(yīng)的數(shù)據(jù)沒(méi)有被刪除,而且屏幕上顯示的RecyclerView沒(méi)有被刷新,這些處理需要在onSwiped方法中處理,代碼如下:

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            //滑動(dòng)處理
            int position = viewHolder.getAdapterPosition();
            if(list != null && list.size() > 0){
                //刪除List中對(duì)應(yīng)的數(shù)據(jù)
                list.remove(position);

                if (recycleViewAdapter == null){
                    return;
                }
                //刷新頁(yè)面
                recycleViewAdapter.notifyItemRemoved(position);

            }
        }
    };

效果如下:

361.gif
(5)getMoveThreshold: 設(shè)置拖拽距離百分比

看一下以下方法:

        @Override
        public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
            return .5f;
        }

如果RecyclerView是垂直方向,那么當(dāng)拖拽到當(dāng)前Item高度的50%時(shí)開(kāi)始執(zhí)行onMove方法。

下面我將貼出兩張圖,分別表示0.5和5的情況:

返回值為0.5的情況:

359.gif

返回值為4的情況:

362.gif
(6)getMoveThreshold: 設(shè)置拖拽距離百分比
        @Override
        public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
            //返回值滑動(dòng)消失的距離, 這里是相對(duì)于RecycleView的寬度,0.5f表示為RecycleView的寬度的一半,取值為0~1f之間
            return .5f;
        }

它的返回值默認(rèn)為50%,一般沒(méi)有特殊需求就按照默認(rèn)。

(7)getSwipeEscapeVelocity: 精確的計(jì)算出滑動(dòng)消失的距離
        @Override
        public float getSwipeEscapeVelocity(float defaultValue) {
            //返回值滑動(dòng)消失的距離,滑動(dòng)小于這個(gè)值不消失,大于消失,默認(rèn)為屏幕的三分之一
            //defaultValue默認(rèn)值為120dp,轉(zhuǎn)成px為 defaultValue * density
            return defaultValue;
        }

defaultValue默認(rèn)值為120dp,轉(zhuǎn)成px為defaultValue * density(density為像素縮放因子)

(8)getSwipeVelocityThreshold: 控制慣性速率
        @Override
        public float getSwipeVelocityThreshold(float defaultValue) {
            //設(shè)置滑動(dòng)速率,這里的速率是指以一定的速率滑動(dòng)Item,松開(kāi)時(shí)Item依然從某一個(gè)方向移動(dòng)的速率(可以理解為慣性的速率)
            //defaultValue默認(rèn)值為800dp,轉(zhuǎn)成px為 defaultValue * density
            return defaultValue;
        }

defaultValue默認(rèn)值為800dp,轉(zhuǎn)成px為 defaultValue * density(density為像素縮放因子)

(9)isLongPressDragEnabled: 是否允許長(zhǎng)按拖拽
        @Override
        public boolean isLongPressDragEnabled() {
            return true;
        }

它的返回值默認(rèn)為true。

(10)isItemViewSwipeEnabled: 是否允許左右滑動(dòng)刪除
        @Override
        public boolean isItemViewSwipeEnabled() {
            return true
        }

它的返回值默認(rèn)為true。

(11)onSelectedChanged: 拖拽或滑動(dòng)時(shí)被調(diào)用
        @Override
        public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
            super.onSelectedChanged(viewHolder, actionState);
        }

從靜止?fàn)顟B(tài)變?yōu)橥献Щ蛘呋瑒?dòng)的時(shí)候會(huì)回調(diào)該方法,參數(shù)actionState表示當(dāng)前的狀態(tài)。

這個(gè)方法可以用于處理在拖拽或者滑動(dòng)時(shí)的UI變化。

(12)getAnimationDuration: 設(shè)置動(dòng)畫(huà)時(shí)間
        @Override
        public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
            return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
        }

當(dāng)手指松開(kāi)時(shí),Item會(huì)移動(dòng)到某個(gè)固定的位置,這個(gè)動(dòng)作就是Item動(dòng)畫(huà),而getAnimationDuration方法可以設(shè)置動(dòng)畫(huà)的時(shí)間,默認(rèn)為200ms或者250ms。

(13)clearView: 初始化話(huà),清空View的狀態(tài)
        @Override
        public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            super.clearView(recyclerView, viewHolder);
        }

當(dāng)拖拽或滑動(dòng)動(dòng)畫(huà)結(jié)束時(shí),也就是手指松開(kāi)并等待動(dòng)畫(huà)結(jié)束時(shí)會(huì)執(zhí)行clearView方法,這個(gè)方法可以用來(lái)初始化數(shù)據(jù)。

(14)onChildDraw: 在Item底部繪制圖形
        @Override
        public void onChildDraw(@NonNull Canvas canvas, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }

onChildDraw方法有如下幾個(gè)參數(shù):

  • canvas: 畫(huà)布,可以用于繪制圖形
  • recyclerView:RecyclerView對(duì)象
  • viewHolder:被操作的Item
  • dX:Item被操作時(shí)的X軸方向的偏移量
  • dY:Item被操作時(shí)的Y軸方向的偏移量
  • actionState:移動(dòng)狀態(tài),在前文已經(jīng)給出移動(dòng)的三種狀態(tài):無(wú)操作狀態(tài)、拖拽狀態(tài)、滑動(dòng)狀態(tài)
  • isCurrentlyActive:滑動(dòng)分為兩類(lèi)。其一:手指滑動(dòng);其二:Item位移動(dòng)畫(huà)滑動(dòng);isCurrentlyActive可以用于判斷是哪種滑動(dòng),如果isCurrentlyActive為true則表示手指滑動(dòng)

我們看一下以下代碼

        private Paint paint;
        private RectF rect;

        @Override
        public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

            //Item底部底部繪制圖形
            c.translate(-dX, 0);
            paint = new Paint();
            paint.setColor(Color.RED);
            paint.setStyle(Paint.Style.FILL);

            //在布局中,我設(shè)置的是4dp,這里需要轉(zhuǎn)成px
            float padding = 4 * getResources().getDisplayMetrics().density + 0.5f;

            //獲取X軸Item位置
            float x = viewHolder.itemView.getX() + padding;
            float y = viewHolder.itemView.getY() + padding;
            float width = viewHolder.itemView.getWidth() - 2 * padding;
            float height = viewHolder.itemView.getHeight() - 2 * padding;
            rect = new RectF(x, y, x + width, y + height);
            c.drawRect(rect, paint);

        }

代碼的意思也很簡(jiǎn)單,就是使用Canvas繪制一個(gè)矩形,演示效果如下:

363.gif
(15)onChildDrawOver: 在Item上面繪制圖形
        @Override
        public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }

onChildDrawOver方法有如下幾個(gè)參數(shù):

  • canvas: 畫(huà)布,可以用于繪制圖形
  • recyclerView:RecyclerView對(duì)象
  • viewHolder:被操作的Item
  • dX:Item被操作時(shí)的X軸方向的偏移量
  • dY:Item被操作時(shí)的Y軸方向的偏移量
  • actionState:移動(dòng)狀態(tài),在前文已經(jīng)給出移動(dòng)的三種狀態(tài):無(wú)操作狀態(tài)、拖拽狀態(tài)、滑動(dòng)狀態(tài)
  • isCurrentlyActive:滑動(dòng)分為兩類(lèi)。其一:手指滑動(dòng);其二:Item位移動(dòng)畫(huà)滑動(dòng);isCurrentlyActive可以用于判斷是哪種滑動(dòng),如果isCurrentlyActive為true則表示手指滑動(dòng)

我們看一下以下代碼

        @Override
        public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            //Item上面繪制圖形
            //c.translate(-dX, 0);
            paint = new Paint();
            paint.setColor(Color.GRAY);
            paint.setStyle(Paint.Style.FILL);

            //在布局中,我設(shè)置的是4dp,這里需要轉(zhuǎn)成px
            float padding = 4 * getResources().getDisplayMetrics().density + 0.5f;

            //獲取X軸Item位置
            float x = viewHolder.itemView.getX() + padding;
            float y = viewHolder.itemView.getY() + padding;
            float width = viewHolder.itemView.getWidth() - 2 * padding;
            float height = viewHolder.itemView.getHeight() - 2 * padding;
            rect = new RectF(x + width - 200, y + height / 2 - 50, x + width - 100, y + height / 2 + 50);
            c.drawRect(rect, paint);
        }

上面代碼的意思是:在Item上面畫(huà)一個(gè)正方形。

效果圖如下:


364.gif

圖中可以看到,Item上已經(jīng)繪制了一個(gè)正方形。

(16)完整代碼
    //聲明一個(gè)Callback
    ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {

        @Override
        public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            //控制拖拽的方向(一般是上下左右)
            int dragFlags= ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            //控制快速滑動(dòng)的方向(一般是左右)
            int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;

            return makeMovementFlags(dragFlags, swipeFlags);//計(jì)算movement flag值
        }

        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            // 拖拽時(shí),每移動(dòng)一個(gè)位置就會(huì)調(diào)用一次。

            if (recyclerView == null){
                return false;
            }

            RecyclerView.Adapter adapter = recyclerView.getAdapter();
            if (adapter == null){
                return false;
            }

            if (list != null && list.size() > 0) {
                //獲取被拖拽的Item的Position
                int from = viewHolder.getAdapterPosition();
                //獲取目標(biāo)Item的Position
                int endPosition = target.getAdapterPosition();
                //交換List集合中兩個(gè)元素的位置
                Collections.swap(list, from, endPosition);
                //交換界面上兩個(gè)Item的位置
                adapter.notifyItemMoved(from, endPosition);
            }
            return true;
        }

        @Override
        public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
            //設(shè)置拖拽距離百分比
            //如果RecyclerView是垂直方向,那么當(dāng)拖拽到當(dāng)前Item高度的50%時(shí)開(kāi)始執(zhí)行onMove方法
            return .5f;
        }

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {

            //滑動(dòng)處理
            int position = viewHolder.getAdapterPosition();
            if(list != null && list.size() > 0){
                //刪除List中對(duì)應(yīng)的數(shù)據(jù)
                list.remove(position);

                if (recycleViewAdapter == null){
                    return;
                }
                //刷新頁(yè)面
                recycleViewAdapter.notifyItemRemoved(position);

            }
        }

        @Override
        public boolean isLongPressDragEnabled() {
            return true;
        }

        @Override
        public boolean isItemViewSwipeEnabled() {
            return true;
        }

        @Override
        public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
            super.onSelectedChanged(viewHolder, actionState);
        }


        private Paint paint;
        private RectF rect;

        @Override
        public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

            //Item底部底部繪制圖形
            c.translate(-dX, 0);
            paint = new Paint();
            paint.setColor(Color.RED);
            paint.setStyle(Paint.Style.FILL);

            //在布局中,我設(shè)置的是4dp,這里需要轉(zhuǎn)成px
            float padding = 4 * getResources().getDisplayMetrics().density + 0.5f;

            //獲取X軸Item位置
            float x = viewHolder.itemView.getX() + padding;
            float y = viewHolder.itemView.getY() + padding;
            float width = viewHolder.itemView.getWidth() - 2 * padding;
            float height = viewHolder.itemView.getHeight() - 2 * padding;
            rect = new RectF(x, y, x + width, y + height);
            c.drawRect(rect, paint);

        }


        @Override
        public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
            return 1000;
        }


        @Override
        public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            super.clearView(recyclerView, viewHolder);
        }

        @Override
        public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            //Item上面繪制圖形
            //c.translate(-dX, 0);
            paint = new Paint();
            paint.setColor(Color.GRAY);
            paint.setStyle(Paint.Style.FILL);

            //在布局中,我設(shè)置的是4dp,這里需要轉(zhuǎn)成px
            float padding = 4 * getResources().getDisplayMetrics().density + 0.5f;

            //獲取X軸Item位置
            float x = viewHolder.itemView.getX() + padding;
            float y = viewHolder.itemView.getY() + padding;
            float width = viewHolder.itemView.getWidth() - 2 * padding;
            float height = viewHolder.itemView.getHeight() - 2 * padding;
            rect = new RectF(x + width - 200, y + height / 2 - 50, x + width - 100, y + height / 2 + 50);
            c.drawRect(rect, paint);
        }


        @Override
        public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
            //返回值滑動(dòng)消失的距離, 這里是相對(duì)于RecycleView的寬度,0.5f表示為RecycleView的寬度的一半,取值為0~1f之間
            return .5f;
        }

        @Override
        public float getSwipeEscapeVelocity(float defaultValue) {
            //返回值滑動(dòng)消失的距離,滑動(dòng)小于這個(gè)值不消失,大于消失,默認(rèn)為屏幕的三分之一
            //defaultValue默認(rèn)值為120dp,轉(zhuǎn)成px為 defaultValue * density
            return defaultValue;
        }

        @Override
        public float getSwipeVelocityThreshold(float defaultValue) {
            //設(shè)置滑動(dòng)速率,這里的速率是指以一定的速率滑動(dòng)Item,松開(kāi)時(shí)Item依然從某一個(gè)方向移動(dòng)的速率(可以理解為慣性的速率)
            //defaultValue默認(rèn)值為800dp,轉(zhuǎn)成px為 defaultValue * density
            return defaultValue;
        }
    };
    //創(chuàng)建helper對(duì)象
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
    //關(guān)聯(lián)recyclerView
    itemTouchHelper.attachToRecyclerView(recyclerview);

以上代碼只要演示一遍,基本就會(huì)明白ItemTouchHelper的作用,ItemTouchHelper常用方法是getMovementFlags、onMove、onSwiped,強(qiáng)烈建議重點(diǎn)學(xué)習(xí)。

[本章完...]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容