這篇文章會(huì)講解RecyclerView的Item拖動(dòng)排序與滑動(dòng)刪除椭蹄。
ItemTouchHelper
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
ItemTouchHelper是一個(gè)支持RecyclerView的滑動(dòng)刪除和拖拽的工具類(lèi)杨何。也就是說(shuō)我們可以通過(guò)它來(lái)簡(jiǎn)單的完成RecyclerView的Item拖動(dòng)排序與滑動(dòng)刪除。
效果如圖
拖動(dòng)和滑動(dòng).gif
一哩陕、使用ItemTouchHelper.Callback
要使用ItemTouchHelper需要?jiǎng)?chuàng)建一個(gè)類(lèi)繼承 ItemTouchHelper.Callback 抽象類(lèi)平项,通過(guò)這個(gè)類(lèi)可以讓你監(jiān)聽(tīng)“move”與 “swipe”事件,而且還可以控制view被選中的狀態(tài)以及重寫(xiě)默認(rèn)動(dòng)畫(huà)的地方萌踱。如果你只是想要一個(gè)基本的實(shí)現(xiàn)葵礼,有一個(gè)系統(tǒng)封裝好的可以使用:SimpleCallback。但是為了了解其工作機(jī)制并鸵,我們還是自己實(shí)現(xiàn)鸳粉。
這是這個(gè)類(lèi)需要些的全部代碼
public class ItemTouchHelperCallback extends ItemTouchHelper.Callback{
private ItemTouchHelperAdapter itemTouchHelperAdapter;//RecyclerView的適配器
/**
* 多參的構(gòu)造方法
* @param itemTouchHelperAdapter 需要適配器來(lái)改變數(shù)據(jù)的位置,以及通知它來(lái)刷新
*/
public ItemTouchHelperCallback(ItemTouchHelperAdapter itemTouchHelperAdapter) {
this.itemTouchHelperAdapter = itemTouchHelperAdapter;
}
/**
* RecyclerView item支持長(zhǎng)按進(jìn)入拖動(dòng)操作
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* RecyclerView item任意位置觸發(fā)啟用滑動(dòng)操作
*/
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
/**
* 指定可以支持的拖動(dòng)和滑動(dòng)的方向园担,上下為拖動(dòng)(drag)届谈,左右為滑動(dòng)(swipe)
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//判斷布局管理器是否為GridLayoutManager
if (recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//不需要滑動(dòng)
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);
}
}
/**
* 拖動(dòng)操作會(huì)執(zhí)行的方法
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//判斷如果viewHolder類(lèi)型不一樣,返回False
if (viewHolder.getItemViewType() != target.getItemViewType()) {
return false;
}
//通知適配器改變數(shù)據(jù) 以及刷新
itemTouchHelperAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
/**
* 滑動(dòng)操作會(huì)執(zhí)行的方法
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//通知適配器刪除數(shù)據(jù) 以及刷新
itemTouchHelperAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
/**
* 當(dāng)動(dòng)作開(kāi)始的時(shí)候調(diào)用
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
//動(dòng)作不是空閑狀態(tài)調(diào)用
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
if (viewHolder instanceof ItemTouchHelperAdapter.ItemTouchHelperViewHolder) {
//獲取執(zhí)行的item的ViewHolder
ItemTouchHelperAdapter.ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperAdapter.ItemTouchHelperViewHolder) viewHolder;
//選中狀態(tài)回調(diào)
itemViewHolder.onItemSelected();
}
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 當(dāng)動(dòng)作之中的時(shí)候調(diào)用
*/
@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) {
//自定義滑動(dòng)動(dòng)畫(huà)(讓它根據(jù)滑動(dòng)的距離與itemView的寬度的比例來(lái)改變透明度)
final float alpha = 1.0f - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
//設(shè)置透明度
viewHolder.itemView.setAlpha(alpha);
//設(shè)置平移動(dòng)畫(huà)
viewHolder.itemView.setTranslationX(dX);
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
/**
* 當(dāng)動(dòng)作結(jié)束的時(shí)候調(diào)用
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
if (viewHolder instanceof ItemTouchHelperAdapter.ItemTouchHelperViewHolder) {
//獲取執(zhí)行的item的ViewHolder
ItemTouchHelperAdapter.ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperAdapter.ItemTouchHelperViewHolder) viewHolder;
//未選中狀態(tài)回調(diào)
itemViewHolder.onItemNormal();
}
}
}
- 繼承ItemTouchHelper.Callback的抽象類(lèi)之后會(huì)讓你實(shí)現(xiàn)這三個(gè)方法
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)
- getMovementFlags在這個(gè)方法里面寫(xiě)通過(guò)item的移動(dòng)方向來(lái)判斷是拖動(dòng)或滑動(dòng)操作弯汰。
- onMove在這個(gè)方法里面寫(xiě)拖動(dòng)操作后的執(zhí)行方法艰山,通過(guò)適配器來(lái)改變數(shù)據(jù)位置,以及刷新
- onSwiped在這個(gè)方法里面寫(xiě)滑動(dòng)操作后的執(zhí)行方法咏闪,通過(guò)適配器來(lái)刪除數(shù)據(jù)位置曙搬,以及刷新
- 之后還需要些兩個(gè)輔助動(dòng)作的方法
@Override
public boolean isLongPressDragEnabled()
@Override
public boolean isItemViewSwipeEnabled()
- isLongPressDragEnabled這個(gè)方法默認(rèn)返回ture,支持長(zhǎng)按進(jìn)入拖動(dòng)操作
- isItemViewSwipeEnabled這個(gè)方法指的是在view任意位置觸摸事件發(fā)生時(shí)啟用滑動(dòng)操作
- 如果寫(xiě)一些在有關(guān)操作的動(dòng)畫(huà)鸽嫂,復(fù)寫(xiě)下面三個(gè)方法
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
- onSelectedChanged指的是你在開(kāi)始操作(也就是說(shuō)選中item)的時(shí)候希望做的對(duì)item的改變纵装,比如說(shuō)改變item的背景顏色,還可以通過(guò)參數(shù)actionState來(lái)判斷什么操作
- onChildDraw指的是你在操作(一般指的是滑動(dòng))途中希望做的對(duì)item的改變据某,比如寫(xiě)了一個(gè)透明度改變的動(dòng)畫(huà)
- clearView操作結(jié)束后的做的對(duì)item的改變橡娄,讓它恢復(fù)原有狀態(tài)
二、需要在Adapter寫(xiě)的方法
全部的代碼
public class ItemTouchHelperAdapter extends RecyclerView.Adapter<ItemTouchHelperAdapter.ItemTouchHelperViewHolder> {
private ArrayList<String> list;//要顯示的數(shù)據(jù)
private Context context;//上下文
private ImgViewTouchListener imgViewTouchListener;//需要外面實(shí)現(xiàn)的接口
/*
多參的構(gòu)造方法
*/
public ItemTouchHelperAdapter(ArrayList<String> list, Context context) {
this.list = list;
this.context = context;
}
/**
* 創(chuàng)建視圖
*/
@Override
public ItemTouchHelperViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//創(chuàng)建視圖
View view = LayoutInflater.from(context).inflate(R.layout.item_touch_helper_item,parent,false);
//實(shí)例化MainViewHolder---- 傳View過(guò)去
ItemTouchHelperViewHolder holder = new ItemTouchHelperViewHolder(view);
return holder;
}
/**
* 初始化控件
*/
public class ItemTouchHelperViewHolder extends RecyclerView.ViewHolder{
public TextView textView;
public ImageView imageView;
public ItemTouchHelperViewHolder(View itemView) {
super(itemView);
//初始化控件
textView = (TextView) itemView.findViewById(R.id.text);
imageView = (ImageView) itemView.findViewById(R.id.imgView);
}
/**
* 操作開(kāi)始時(shí)調(diào)用的方法
*/
public void onItemSelected() {
itemView.setBackgroundColor(Color.BLACK);
}
/**
* 操作完成后調(diào)用的方法
*/
public void onItemNormal() {
itemView.setBackgroundColor(0);
}
}
/**
* 填充數(shù)據(jù)
*/
@Override
public void onBindViewHolder(final ItemTouchHelperViewHolder holder, int position) {
//獲取要填充的值
String content = list.get(position);
//控件中設(shè)置值
holder.textView.setText(content);
holder.imageView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
imgViewTouchListener.imgViewOnTouch(event,holder);
return false;
}
});
}
/**
* 獲取item的總個(gè)數(shù)
*/
@Override
public int getItemCount() {
return list.size();
}
/**
* 拖動(dòng)方法
*/
public boolean onItemMove(int fromPosition, int toPosition) {
//互換列表中指定位置的數(shù)據(jù)
Collections.swap(list, fromPosition, toPosition);
//通知改變
notifyItemMoved(fromPosition, toPosition);
return true;
}
/**
* 滑動(dòng)刪除的方法
*/
public void onItemDismiss(int position) {
list.remove(position);
notifyItemRemoved(position);
}
/*
暴露出去的點(diǎn)擊事件的方法
*/
public void setImgViewTouchListener(ImgViewTouchListener imgViewTouchListener){
this.imgViewTouchListener = imgViewTouchListener;
}
/*
點(diǎn)擊要實(shí)現(xiàn)的接口
*/
public interface ImgViewTouchListener{
public void imgViewOnTouch(MotionEvent event,ItemTouchHelperViewHolder holder);
}
}
- 寫(xiě)一個(gè)拖動(dòng)操作調(diào)用的方法和一個(gè)滑動(dòng)刪除調(diào)用的方法癣籽,在上一個(gè)類(lèi)的onMove和onSwiped方法中調(diào)用挽唉。
- 在ViewHolder內(nèi)部類(lèi)寫(xiě)開(kāi)始操作和結(jié)束操作的方法滤祖,在上一個(gè)類(lèi)的onSelectedChanged和clearView方法中調(diào)用
- 最后我希望在按下圖片才開(kāi)始拖拽操作,所有需要寫(xiě)一個(gè)點(diǎn)擊方法(通過(guò)上一篇文章的方式)瓶籽。
三匠童、在Activity中
//實(shí)例化ItemTouchHelper對(duì)象
final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelperCallback(adapter));
//itemTouchHelper與RecyclerView關(guān)聯(lián)
itemTouchHelper.attachToRecyclerView(rcTouch);
//設(shè)置ImgView的觸摸監(jiān)聽(tīng)事件
adapter.setImgViewTouchListener(new ItemTouchHelperAdapter.ImgViewTouchListener() {
@Override
public void imgViewOnTouch(MotionEvent event, ItemTouchHelperAdapter.ItemTouchHelperViewHolder holder) {
//判斷是否按下圖片
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
//按下則開(kāi)始拖動(dòng)
itemTouchHelper.startDrag(holder);
}
}
});
- 首先實(shí)例化一個(gè)ItemTouchHelper類(lèi),并且在參數(shù)之前寫(xiě)的ItemTouchHelperCallback類(lèi)的對(duì)象
- 然后將其與RecyclerView關(guān)聯(lián)
- 設(shè)置ImgView的觸摸監(jiān)聽(tīng)棘劣,在里面通過(guò)ItemTouchHelper類(lèi)來(lái)調(diào)用開(kāi)始拖動(dòng)的方法
RecyclerView的系列的文章
- 第一篇RecyclerView的基本使用 RecyclerView使用(一)
- 第二篇有關(guān)多種Item,添加俏让,刪除 RecyclerView使用(二)
- 第三篇RecyclerView的監(jiān)聽(tīng)方法RecyclerView使用(三)
- 第四篇RecyclerView的拖動(dòng)和滑動(dòng)刪除RecyclerView使用(四)