Android ItemTouchHelper 實踐

吳小龍同學發表於2019-03-03

實現RecyclerView拖動排序和滑動刪除,我想到的是 ViewDragHelper ,或者是第三方庫,當我看了 ToDoList 的時候,發現原來官方已經支援RecyclerView拖動排序與滑動刪除,那就是ItemTouchHelper。

簡介

“ItemTouchHelper is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.

It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.

Depending on which functionality you support, you should override onMove(RecyclerView, ViewHolder, ViewHolder) and / or onSwiped(ViewHolder, int).”

ItemTouchHelper 實現RecyclerView拖動排序和滑動刪除,我們需要重寫方法:

int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)複製程式碼

指定可以支援的拖放和滑動的方向,上下為拖動(drag),左右為滑動(swipe)

onMove(RecyclerView, ViewHolder, ViewHolder)複製程式碼

滑動操作

onSwiped(ViewHolder, int)複製程式碼

刪掉操作

實踐

依賴

app/build.gradle

compile 'com.android.support:recyclerview-v7:25.0.0'複製程式碼

效果預覽

線性

Android ItemTouchHelper 實踐

網格
Android ItemTouchHelper 實踐

ItemTouchHelperCallback

新建ItemTouchHelperCallback繼承ItemTouchHelper.Callback,完整程式碼如下:

public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
    private ItemTouchHelperAdapter itemTouchHelperAdapter;
    private float ALPHA_FULL = 1.0f;

    ItemTouchHelperCallback(ItemTouchHelperAdapter itemTouchHelperAdapter) {
        this.itemTouchHelperAdapter = itemTouchHelperAdapter;
    }

    /**
     * RecyclerView item支援長按進入拖動操作
     */
    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    /**
     * RecyclerView item任意位置觸發啟用滑動操作
     */
    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }

    /**
     * 指定可以支援的拖放和滑動的方向,上下為拖動(drag),左右為滑動(swipe)
     */
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        if (recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
            final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            //不需要滑動
            final int swipeFlags = 0;
            return makeMovementFlags(dragFlags, swipeFlags);
        } else {
            final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
            return makeMovementFlags(dragFlags, swipeFlags);
        }
    }

    /**
     * 滑動操作
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        if (viewHolder.getItemViewType() != target.getItemViewType()) {
            return false;
        }
        // Notify the adapter of the move
        itemTouchHelperAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    /**
     * 刪掉操作
     */
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        itemTouchHelperAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            //自定義滑動動畫
            final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
            viewHolder.itemView.setAlpha(alpha);
            viewHolder.itemView.setTranslationX(dX);
        } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    }

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        // We only want the active item to change
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            if (viewHolder instanceof ItemTouchHelperViewHolder) {
                // Let the view holder know that this item is being moved or dragged
                ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
                //選中狀態回撥
                itemViewHolder.onItemSelected();
            }
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        viewHolder.itemView.setAlpha(ALPHA_FULL);
        if (viewHolder instanceof ItemTouchHelperViewHolder) {
            // Tell the view holder it's time to restore the idle state
            ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
            //未選中狀態回撥
            itemViewHolder.onItemClear();
        }
    }
}複製程式碼

attachToRecyclerView

建立ItemTouchHelper物件,然後呼叫attachToRecyclerView(RecyclerView) 方法

ItemTouchHelperCallback itemTouchHelperCallback = new ItemTouchHelperCallback(recyclerViewAdatper);
itemTouchHelper = new ItemTouchHelper(itemTouchHelperCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);複製程式碼

原始碼

更多詳見原始碼:github.com/WuXiaolong/… ,很多參考了iPaulPro/Android-ItemTouchHelper-Demo,關鍵需要消化,轉化成自己的東西。

參考

官網Api
Drag and Swipe with RecyclerView
Drag and Swipe with RecyclerView—Part Two

聯絡我

我的微信公眾號:吳小龍同學,歡迎關注交流~

Android ItemTouchHelper 實踐

QQ群

Android ItemTouchHelper 實踐

相關文章