ItemTouchHelper實現(xiàn)RecyclerView拖動排序和滑動刪除

前言

最近在項目中有需求使用RecyclerView的滑動刪除或者左滑顯示刪除按鈕,類似QQ消息列表滑動效果一樣

在網(wǎng)上有許多大神貢獻出來的實現(xiàn)這種效果的項目,最近在學(xué)習(xí)自定義View,想著能不能自己倒騰出來一個了。結(jié)果沒出一會兒就在網(wǎng)上看到Google針對RecyclerView是有提供一個專門的工具類,看了一下官網(wǎng)資料,看了一些網(wǎng)上的資料就開始搞事了=。=

ItemTouchHelper 源碼介紹

按照官網(wǎng)介紹這就是為RecyclerView專門定制的。按照我一貫的邏輯,先進源碼看看再說

首先看看其繼承關(guān)系:

public class ItemTouchHelper extends RecyclerView.ItemDecoration
        implements RecyclerView.OnChildAttachStateChangeListener

我們都知道RecyclerView.ItemDecoration是用來一個用來修飾RecyclerView的子item的抽象類,也就知道它的作用是什么了。

再來看看構(gòu)造方法:

/**
     * Creates an ItemTouchHelper that will work with the given Callback.
     
     * @param callback The Callback which controls the behavior of this touch helper.
     */
    public ItemTouchHelper(Callback callback) {
        mCallback = callback;
    }

需要傳入一個CallBack對象,我們先來看看這個callback對象是什么東西:

public abstract static class Callback {

     ............
         //拖動
         public abstract boolean onMove(RecyclerView recyclerView,
                ViewHolder viewHolder, ViewHolder target);
         //滑動
         public abstract void onSwiped(ViewHolder viewHolder, int direction);
.........
}

一個ItemTouchHelper內(nèi)部的抽象類,在下面看到源碼已經(jīng)提供了一個簡單的實現(xiàn)類SimpleCallback,任然是一個抽象類,但是使用他已經(jīng)足夠?qū)崿F(xiàn)我的需求了,或者自己再添加其他功能也是可以的

再往下看見一個GestureDetector的實現(xiàn)類:

private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener

還有就是

private class RecoverAnimation implements AnimatorListenerCompat

這兩個暫時先沒有具體的研究性。看到底了,對了還沒看到是如何和RecyclerView綁定的呢,往上翻翻,才注意到原來是在這里:

public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
        if (mRecyclerView == recyclerView) {
            return; // nothing to do
        }
        if (mRecyclerView != null) {
            destroyCallbacks();
        }
        mRecyclerView = recyclerView;
        if (mRecyclerView != null) {
            final Resources resources = recyclerView.getResources();
            mSwipeEscapeVelocity = resources
                    .getDimension(R.dimen.item_touch_helper_swipe_escape_velocity);
            mMaxSwipeVelocity = resources
                    .getDimension(R.dimen.item_touch_helper_swipe_escape_max_velocity);
            setupCallbacks();
        }
    }

這里先判斷現(xiàn)有的mRecyclerView和傳入的recyclerView是否是同一個,如果是同一個什么都不做,再判斷mRecyclerView是否存在,不存在則銷毀Callback。判斷后則是將傳入的recyclerView賦給mRecyclerView,然后調(diào)用setupCallbacks()方法:

private void setupCallbacks() {
        ViewConfiguration vc = ViewConfiguration.get(mRecyclerView.getContext());
        mSlop = vc.getScaledTouchSlop();
        mRecyclerView.addItemDecoration(this);
        mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);
        mRecyclerView.addOnChildAttachStateChangeListener(this);
        initGestureDetector();
    }

只是對進行一些基礎(chǔ)的初始化操作,然后調(diào)用initGestureDetector()方法創(chuàng)建了ItemTouchHelperGestureListener的實例

private void initGestureDetector() {
        if (mGestureDetector != null) {
            return;
        }
        mGestureDetector = new GestureDetectorCompat(mRecyclerView.getContext(),
                new ItemTouchHelperGestureListener());
    }

其他還有許多其他方法,包括移動,滑動,刪除,繪制,動畫等等,具體多的就不說了??戳艘灿洸蛔?。=

RecyclerView拖動排序和滑動刪除

說了那么多,接下來就是實戰(zhàn)時間了。直接貼代碼,相信結(jié)合代碼中的注釋一看就能明白了

首先是自定義的ItemTouchHelper

/**
     * dragDirs - 表示拖拽的方向,有六個類型的值:LEFT、RIGHT、START、END、UP、DOWN
       swipeDirs - 表示滑動的方向,有六個類型的值:LEFT、RIGHT、START、END、UP、DOWN
     */
    ItemTouchHelper.Callback callback=new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP|ItemTouchHelper.DOWN,ItemTouchHelper.RIGHT) {
        /**
         *
         * @param recyclerView 綁定的RecyclerView
         * @param viewHolder 需要拖動的ViewHolder
         * @param target  目標(biāo)位置的ViewHolder
         * @return
         */
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            int from=viewHolder.getAdapterPosition();
            int to=target.getAdapterPosition();
            /**
             * 這里拖動的想法是往下拖動則把中間的所有item上移
             * 往下則把所有的item下移
             * 如果想實現(xiàn)拖動前后位置item的交換  即只需要交換兩個位置的item
             */
            if (from<to){
                //中間上移
                for (int i=from;i < to;i++){
                    Collections.swap(list,i,i+1);
                }
            }else {
                for (int i=from;i>to;i--){
                    Collections.swap(list,i,i-1);
                }
            }
            adapter.notifyItemMoved(from,to);
            //return true表示執(zhí)行移動
            return true;
        }

        /**
         *
         * @param viewHolder 滑動的RecyclerView
         * @param direction 滑動的方向
         */
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            int position=viewHolder.getAdapterPosition();
            list.remove(position);
            adapter.notifyItemRemoved(position);
        }

        @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
                //滑動時改變Item的透明度
                final float alpha = 1 - Math.abs(dX) / (float)viewHolder.itemView.getWidth();
                viewHolder.itemView.setAlpha(alpha);
                viewHolder.itemView.setTranslationX(dX);
            }
        }
    };

然后結(jié)合RecyclerView使用:

 protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.swipedelete_dragchange_recyclerview);
        ButterKnife.bind(this);
        list=new ArrayList<>();
        for (int i=0;i<50;i++){
            list.add("RecyclerView Item "+i);
        }
        adapter=new MyRecyclerViewAdapter(this,list);
        swipeDeleteDragChangeRecyclerview.setLayoutManager(new LinearLayoutManager(this));
        swipeDeleteDragChangeRecyclerview.setItemAnimator(new DefaultItemAnimator());
        swipeDeleteDragChangeRecyclerview.setHasFixedSize(true);
        ItemTouchHelper helper=new ItemTouchHelper(callback);
        helper.attachToRecyclerView(swipeDeleteDragChangeRecyclerview);
        swipeDeleteDragChangeRecyclerview.setAdapter(adapter);

    }

目前就寫了這么一些,以后有深入研究或者有其他實現(xiàn)方法也會更新。
源碼地址

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

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

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