首先說一下關鍵點热康,在RecyclerView中實現(xiàn)拖拽排序時非常簡單地惭笑,只需要個給RecyclerView添加一個ItemTouchHelper就可以實現(xiàn),具體實現(xiàn)如下:
1.創(chuàng)建ItemTouchHelper對象并綁定
final ItemTouchHelper itemTouchHelp = new ItemTouchHelper(new CityRecycleCallBack(adapter));
itemTouchHelp.attachToRecyclerView(recyclerView);
創(chuàng)建對象時需要一個回調昼弟,我們具體看看這個回調怎么寫
2. ItemTouchHelper.Callback回調實現(xiàn)
這個回調中有許多方法蕾殴,通多對方法的實現(xiàn)就能最終實現(xiàn)拖拽效果
2.1 getMovementFlags
在這里主要設置拖拽的方向即是否可拖拽,根據(jù)布局的不同有不同的方法黄伊,如列表只有上下拖拽泪酱,網(wǎng)格只有上下左右。具體實現(xiàn)如下:
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
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 = 0;
return makeMovementFlags(dragFlags,swipeFlags);
}
}
2.2 onMove
這是一個關鍵方法还最,它在我們拖動時不斷得到調用墓阀,我們要及時更新item的位置,對數(shù)據(jù)進行更新拓轻,具體實現(xiàn)如下:
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
adapter.move(fromPosition,toPosition);
return true;
}
首先獲得起始位置和到達位置斯撮,然后交給adapter處理:
public void move(int fromPosition,int toPosition){
positionChange = true;
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(allCity, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(allCity, i, i - 1);
}
}
notifyItemMoved(fromPosition, toPosition);
}
類似于數(shù)組的插入,將被拖拽的item不斷插入目標位置扶叉,雖然改變的item但我們實際調整的是存放數(shù)據(jù)的list勿锅,每次插入后更新RecyclerView
2.3 onSwiped
這個是拖拽后的回調帕膜,一般不用理會,也可以根據(jù)需求實現(xiàn)一些邏輯
2.4 isLongPressDragEnabled
默認情況下實現(xiàn)的時長按開始拖拽溢十,如果像我示例中那樣點擊某個區(qū)域就開始拖拽垮刹,或者指定某些模塊不可拖拽時,這個方法要返回false张弛。如果都是長按拖拽就要返回true
2.5 onSelectedChanged
這個是在謀和item被選中開始拖拽時的回調荒典,可以像我那樣修改選中的item透明度或者震動一下等都是常見的處理:
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setAlpha(0.5f);
viewHolder.itemView.setBackgroundColor(0);
}
}
2.6 clearView
這個是松開后的回調,一般要將item恢復原樣:
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(1);
}
3.特殊情況的處理
3.1 按住某塊區(qū)域就開始拖拽
如開頭GIF圖中所示乌庶,點擊item的拖拽圖標就可以進行拖拽种蝶,同時禁止長按拖拽的邏輯,首先isLongPressDragEnabled要返回false:
@Override
public boolean isLongPressDragEnabled() {
return false;
}
之后對拖拽圖標進行觸摸監(jiān)聽,在adapter的onBindViewHolder中:
holder.ivSort.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEventCompat.getActionMasked(event) ==
MotionEvent.ACTION_DOWN) {
mDragStartListener.onStartDrag(holder);
}
return false;
}
});
這里要在adapter中添加設置回調的方法:
public void setOnDragStartListener(OnStartDragListener mDragStartListener){
this.mDragStartListener = mDragStartListener;
}
最后ItemTouchHelper在和RecyclerView綁定后設置監(jiān)聽:
adapter.setOnDragStartListener(new OnStartDragListener() {
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
itemTouchHelp.startDrag(viewHolder);
}
});
可以看到關鍵的就一句itemTouchHelp.startDrag(viewHolder)瞒大,這一句話控制某個item處于拖拽狀態(tài)螃征。
3.2 有區(qū)分的進行拖拽
有時候有些item是不可以拖拽的,我們首先在isLongPressDragEnabled中也要返回false透敌。然后在item的長按中進行區(qū)分:
@Override
public void onItemLongClick(RecyclerView.ViewHolder vh) {
if (ViewHolder符合拖拽條件時) {
itemTouchHelp.startDrag(vh);
}
}