如何在RecyclerView上面實現"拖放"和"滑動刪除"-1

 

Android上面有許多的教程, 庫和示例, 在RecyclerView上面實現"拖放"和"滑動刪除"功能. 儘管有更新, 更好的方法可用, 可是大多數人依然使用舊的View.OnDragListener和Roman Nurik的SwipeToDismiss方式. 除了常常使用GestureDetector和onInterceptTouchEvent以外, 幾乎不多有人使用新的API, 要否則的話, 實現就複雜. 事實上真的有十分簡單的方式在RecyclerView上面添加這兩個功能. 它只要求一個類, 並且這個類已是Android支持包的一部分.
html

 

ItemTouchHelperandroid

 

ItemTouchHelper是一個強大的通用程序, 在RecyclerView上面添加"拖放"和"滑動刪除"時, 你所須要作的全部事情, 它都會負責處理. 它是RecyclerView.ItemDecoration的子類, 這意味着它能夠輕易地添加到任何已經存在的LayoutManager和Adapter上面! 它不會影響添加到item上的動畫, 而且支持類別嚴格的"拖", 以及"放"時的動畫, 還能夠支持更多. git

 

準備:github

首先, 咱們所須要的是添加RecyclerView的依賴: ide

1 compile 'com.android.support:recyclerview-v7:25.3.0'

 

使用ItemTouchHelper和ItemTouchHelper.Callback:學習

爲了使用ItemTouchHelper, 你將建立一個ItemTouchHelper.Callback, 這是一個接口, 容許你監聽"move"和"swipe"事件, 並且你能夠經過Callback來控件已選中view的狀態, 而且能夠改變該view的默認動畫. 若是隻是想要一個基礎實現, 你可使用SimpleCallback這個幫助類, 可是爲了學習Callback的工做原理, 咱們將會本身實現一個.動畫

 

爲了激活基本的"拖放"和"滑動刪除", 咱們必須覆蓋的主要方法是:ui

getMovementFlags(RecyclerView, ViewHolder)
onMove(RecyclerView, ViewHolder, ViewHolder)
onSwiped(ViewHolder, int)

咱們也要使用這兩個方法:spa

isLongPressDragEnabled()
isItemViewSwipeEnabled()

咱們一個一個地看一下: code

@Override
public int getMovementFlags(RecyclerView recyclerView, 
        RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
    return makeMovementFlags(dragFlags, swipeFlags);
}

ItemTouchHelper容許你輕易地決定事件的方向.你必須實現getMovementFlags(RecyclerView, RecyclerView.ViewHolder)方法來指明"拖"和"滑動"所支持的方向, 而且使用ItemTouchHelper.makeMovementFlags(int, int)來構建返回標籤. 在此咱們在兩個不一樣的方向激活"拖"和"滑動".

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

ItemTouchHelper可以用來實現"沒有滑動的拖動"或者"沒有拖動的滑動", 因此你必須精確地指明想要支持的動做. 若是你想要在RecyclerView的item上支持"長按啓動拖放"事件, 你就必須實現isLongPressDragEnabled()返回true. 此外, ItemTouchHelper.startDrag(RecyclerView.ViewHolder)能夠從"操做"中啓動"拖放", 這一點會在以後詳述.

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

要想要view內部的任意觸摸事件均可以啓動"滑動"動做, 就簡單地在isItemViewSwipeEnabled()返回true. 此外, ItemTouchHelper.startSwipe(RecyclerView.ViewHolder)可以手動地啓動"滑動"事件.

 

而後, onMove()和onSwiped()方法須要實現, 來通知負責更新基礎數據的東西. 因此, 首先, 咱們要建立一個接口, 以容許咱們傳遞"拖放"和"滑動刪除"事件的回調.

public interface ItemTouchHelperAdapter {

    void onItemMove(int fromPosition, int toPosition);

    void onItemDismiss(int position);
}

從當前示例來說, 要實現這些的最簡單的方式, 是將咱們的RecyclerView.Adapter實現這個接口: 

public class RecyclerListAdapter extends 
        RecyclerView.Adapter<ItemViewHolder> 
        implements ItemTouchHelperAdapter {
// ... code from gist
@Override
public void onItemDismiss(int position) {
    mItems.remove(position);
    notifyItemRemoved(position);
}

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    if (fromPosition < toPosition) {
        for (int i = fromPosition; i < toPosition; i++) {
            Collections.swap(mItems, i, i + 1);
        }
    } else {
        for (int i = fromPosition; i > toPosition; i--) {
            Collections.swap(mItems, i, i - 1);
        }
    }
    notifyItemMoved(fromPosition, toPosition);
    return true;
}

調用notifyItemRemoved(int)和notifyItemMoved(int, int)是很是重要的, 由此, Adapter會更新數據. 請注意, 這也很重要, 咱們改變item的position是在每一次view被切換到新的index, 而不是在"放"事件以後.

 

如今咱們回來構建SimpleItemTouchHelperCallback, 由於咱們依然必須覆蓋onMove()和onSwiped()方法. 首先, 爲Adapter添加構建器和變量:

private final ItemTouchHelperAdapter mAdapter;

public SimpleItemTouchHelperCallback(
        ItemTouchHelperAdapter adapter) {
    mAdapter = adapter;
}

而後覆蓋剩下的事件並通知Adapter:

@Override
public boolean onMove(RecyclerView recyclerView, 
        RecyclerView.ViewHolder viewHolder, 
        RecyclerView.ViewHolder target) {
    mAdapter.onItemMove(viewHolder.getAdapterPosition(), 
            target.getAdapterPosition());
    return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, 
        int direction) {
    mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}

這個Callback應該看起來像這樣: 

public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
 
    private final ItemTouchHelperAdapter mAdapter;

    public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
        mAdapter = adapter;
    }
    
    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

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

    @Override
    public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, 
            ViewHolder target) {
        mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(ViewHolder viewHolder, int direction) {
        mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }

}

當Callback準備好以後, 咱們建立ItemTouchHelper並調用attachToRecyclerView(RecyclerView)方法:

ItemTouchHelper.Callback callback = 
    new SimpleItemTouchHelperCallback(adapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(recyclerView);

當你運行的時候, 結果應該看起來像這樣: 

 

 

總結

 

這是一個ItemTouchHelper極簡單的實現. 可是咱們應該清楚, 在RecyclerView上面實現基本的"拖放"和"滑動刪除", 使用第三方和庫是徹底沒有必要的.

 

示例代碼請點擊這裏.

相關文章
相關標籤/搜索