從ListView開始,就有許多開源的滑動刪除和拖拽的開源庫。不過大多是基于View.OnDragListener實現(xiàn)的窥翩。還有的自己寫touch事件監(jiān)聽各薇,即繁瑣又不優(yōu)雅项贺。RecyclerView的出現(xiàn),讓人耳目一新峭判。拖拽和側(cè)滑的實現(xiàn)當(dāng)然也不能再low了开缎。
正如用GestureDetectorCompat為RecycleView添加點擊事件一樣,拖拽和側(cè)滑Google也有針對RecycleView的api林螃。用起來so easy奕删。
onInterceptTouchEvent
onInterceptTouchEvent類,包含在Android Support Library之中疗认。它的功能正如注釋所說:
/**
* This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
* <p>
* 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.
* <p>
* Depending on which functionality you support, you should override
* {@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder)} and / or
* {@link Callback#onSwiped(ViewHolder, int)}.
* <p>
* This class is designed to work with any LayoutManager but for certain situations, it can be
* optimized for your custom LayoutManager by extending methods in the
* {@link ItemTouchHelper.Callback} class or implementing {@link ItemTouchHelper.ViewDropHandler}
* interface in your LayoutManager.
* <p>
* By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. On
* platforms older than Honeycomb, ItemTouchHelper uses canvas translations and View's visibility
* property to move items in response to touch events. You can customize these behaviors by
* overriding {@link Callback#onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int,
* boolean)}
* or {@link Callback#onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
* boolean)}.
* <p/>
* Most of the time, you only need to override <code>onChildDraw</code> but due to limitations of
* platform prior to Honeycomb, you may need to implement <code>onChildDrawOver</code> as well.
*/
Google為我們實現(xiàn)了兩千多行的代碼急侥。我們需要關(guān)心的只有ItemTouchHelper.Callback接口的三個方法而已。
/**設(shè)置我們拖動的方向以及側(cè)滑的方向的*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
return 0;
}
/**拖動item時會回調(diào)此方法*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
/**側(cè)滑item時會回調(diào)此方法*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
開搞:
第一步侮邀,新建SimpleItemTouchHelperCallback類繼承ItemTouchHelper.Callback坏怪。重寫上述三個方法。由于RecycleView的布局有多種绊茧,所以我們首先要判斷拖拽方向铝宵,如果是ListView形式的,就是上下拖拽,如果的GridvView形式的鹏秋,就上下左右均可拖拽,所以對getMovementFlags重寫:
//如果是ListView樣式的RecyclerView
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager){
//設(shè)置拖拽方向為上下
final int dragFlags = ItemTouchHelper.UP|ItemTouchHelper.DOWN;
//設(shè)置側(cè)滑方向為從左到右和從右到左都可以
final int swipeFlags = ItemTouchHelper.START|ItemTouchHelper.END;
//將方向參數(shù)設(shè)置進去
return makeMovementFlags(dragFlags,swipeFlags);
}else{//如果是GridView樣式的RecyclerView
//設(shè)置拖拽方向為上下左右
final int dragFlags = ItemTouchHelper.UP|ItemTouchHelper.DOWN|
ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;
//不支持側(cè)滑
final int swipeFlags = 0;
return makeMovementFlags(dragFlags,swipeFlags);
}
拖拽后位置的變動需要我們的Adapter數(shù)據(jù)改變才尊蚁,所以聲明一個接口,
public interface onMoveAndSwipedListener {
boolean onItemMove(int fromPosition , int toPosition);
void onItemDismiss(int position);
}
通過構(gòu)造方法傳進來Adapter的監(jiān)聽:
private onMoveAndSwipedListener mAdapter;
public SimpleItemTouchHelperCallback(onMoveAndSwipedListener listener)
{
mAdapter = listener;
}
實現(xiàn)拖拽侣夷,在onMove里調(diào)用:
//回調(diào)adapter中的onItemMove方法
mAdapter.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());
實現(xiàn)側(cè)滑刪除横朋,在onSwiped里調(diào)用:
//回調(diào)adapter中的onItemDismiss方法
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
ItemTouchHelper就編寫好了。百拓。琴锭。簡單吧。下面Adapter去實現(xiàn)著這個回掉接口:
//還是我們的第一個適配器衙传。决帖。。
implements SimpleItemTouchHelperCallback.onMoveAndSwipedListener{
@Override
public boolean onItemMove(int fromPosition, int toPosition)
{
//交換mItems數(shù)據(jù)的位置
Collections.swap(mData,fromPosition,toPosition);
//交換RecyclerView列表中item的位置
notifyItemMoved(fromPosition,toPosition);
return true;
}
@Override
public void onItemDismiss(int position)
{
//刪除mItems數(shù)據(jù)
mData.remove(position);
//刪除RecyclerView列表對應(yīng)item
notifyItemRemoved(position);
}
ok蓖捶。運行試試吧:
想試試多布局地回?用上篇的MoreItemAdapter實現(xiàn)接口:
public class MoreItemAdapter extends MultiItemTypeAdapter<String> implements SimpleItemTouchHelperCallback.onMoveAndSwipedListener
一樣好使。
傳送門:darg分支