通過ItemTouchHelper實現側滑刪除功能
一、效果
二、具體實現
demo中演示的這種左滑刪除的效果在手機APP中比較常用,安卓也為我們提供了專門的輔助類ItemTouchHelper來幫助我們實現這個功能。ItemTouchHelper是一個工具類,可實現側滑刪除和拖拽移動,使用這個工具類需要RecyclerView和Callback。同時根據需要重寫onMove和onSwiped方法。接下來就來講述ItemTouchHelper的使用方法。
具體代碼實現如下:
1、新建接口
從解耦的角度考慮,我們需要一個接口來實現Adapter和ItemTouchHelper之間涉及數據的操作,因為ItemTouchHelper在完成觸摸的各種動畫后,就要對Adapter的數據進行操作,比如側滑刪除操作。因此我們可以把數據操作的部分抽象成一個接口方法,讓ItemTouchHelper.Callback調用該方法即可。
public interface ItemTouchHelperAdapter {
public void onItemDelete(int position);//用來刪除數據
public void onItemRefresh(int position);//當用戶誤操作時用來恢復數據
}
2、在RecyclerView的Adapter類中實現接口中的兩個方法
這里為了讓大家看的清除把整個類都放上來了,其中只有下面兩個方法是接口中的,其他的方法是為了給RecyclerView傳遞數據,詳情可參考RecyclerView的使用方法。
public void onItemDelete(int position);
public void onItemRefresh(int position);
下面是demo中的我的收藏部分源碼
public class MyCollectionAdapter extends RecyclerView.Adapter<MyCollectionAdapter.innerHolder> implements ItemTouchHelperAdapter {
private final ArrayList<ItemCollection> mData;
private MyCollectionAdapter.OnItemClickListener clickListener;
public MyCollectionAdapter(ArrayList<ItemCollection> data){
this.mData = data;
}
@NonNull
@Override
//創建條目View
public MyCollectionAdapter.innerHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.user_item_collection,null);
return new MyCollectionAdapter.innerHolder(view);
}
@Override
//用來綁定holder,設置數據
public void onBindViewHolder(@NonNull MyCollectionAdapter.innerHolder holder, int position) {
holder.setData(mData.get(position),position);
}
@Override
//返回Item的個數
public int getItemCount() {
if(mData != null){
return mData.size();
}
return 0;
}
public void setOnItemClickListener(MyCollectionAdapter.OnItemClickListener listener) {
//設置一個Item的監聽器
clickListener = listener;
}
@Override
public void onItemDelete(int position) {//刪除數據操作,即用戶點擊確定刪除時的邏輯
ItemCollection del = mData.get(position);
String url = "https://api.cnblogs.com/api/bookmarks/" + del.Id;
DeleteApi delapi = new DeleteApi();
@SuppressLint("HandlerLeak")
final Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
if(msg.what == 1){
//刪除成功
System.out.println("成功刪除");
}
}
};
delapi.Delete(handler, url,1);//以上是API的調用刪除網絡數據部分
mData.remove(position);//在本地ItemList中刪除要刪除的Item數據
notifyItemRemoved(position);//提醒RecyclerView,使得后面的數據都向上移動一位
}
@Override
public void onItemRefresh(int position) {//恢復數據,即用戶點擊取消時的邏輯
notifyItemChanged(position);
}
public interface OnItemClickListener {//設置點擊操作
void OnItemClick(int position);
}
public class innerHolder extends RecyclerView.ViewHolder {//用來設置list數據
private TextView title;
private TextView Abstract;
private TextView time;
private int mPosition;
public innerHolder(@NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.item_Collection_blogtitle);
Abstract = itemView.findViewById(R.id.item_Collection_abstract);
time = itemView.findViewById(R.id.item_Collection_time);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clickListener != null) {
clickListener.OnItemClick(mPosition);
}
}
});
}
public void setData(ItemCollection itembean,int position){
this.mPosition = position;
title.setText(itembean.title);
Abstract.setText(itembean.Abstract);
time.setText(itembean.time);
}
}
}
3、新建類繼承自ItemTouchHelper.Callback並重寫方法
從官方文檔我們知道,使用ItemTouchHelper需要一個Callback,該Callback是ItemTouchHelper.Callback的子類,所以我們需要新建一個類比如myItemTouchHelperCallBack繼承自ItemTouchHelper.Callback。我們可以重寫其數個方法來實現我們的需求。下面介紹demo中用到的方法。
public int getMovementFlags(RecyclerView, RecyclerView.ViewHolder)
該方法用於返回可以滑動的方向,比如說允許從右到左側滑,允許上下拖動等。
在本demo中,我們允許Item上下拖動以及從右向左滑,代碼如下:
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//允許上下拖動
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
//允許從右向左滑動
int swipeFlags = ItemTouchHelper.LEFT;
return makeMovementFlags(dragFlags,swipeFlags);
}
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
當用戶拖動一個Item進行上下移動從舊的位置到新的位置的時候會調用該方法,在我們的實例中是禁止這種操作的。
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)
當用戶左右滑動Item達到刪除條件時,會調用該方法,一般手指觸摸滑動的距離達到RecyclerView寬度的一半時,再松開手指,此時該Item會繼續向原先滑動方向滑過去並且調用onSwiped方法進行刪除,否則會反向滑回原來的位置。
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//onItemDelete接口里的方法
showCoverDialog(viewHolder);
}
private void showCoverDialog(final RecyclerView.ViewHolder viewHolder){//跳出提示窗口
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("提示");
builder.setMessage(title);
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {//點擊確定時,刪除數據
itemTouchHelperAdapter.onItemDelete(viewHolder.getAdapterPosition());
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {//點擊取消時恢復Item
@Override
public void onClick(DialogInterface dialogInterface, int i) {
itemTouchHelperAdapter.onItemRefresh(viewHolder.getAdapterPosition());
}
});
builder.show();
}
public boolean isLongPressDragEnabled()
該方法返回true時,表示支持長按拖動,即長按ItemView后才可以拖動,由於默認是true,這里要改為false
public boolean isLongPressDragEnabled() {
//該方法返回值為true時,表示支持長按ItemView拖動
return false;
}
public boolean boolean isItemViewSwipeEnabled()
該方法返回true時,表示如果用戶觸摸並左右滑動了View,那么可以執行滑動刪除操作,即可以調用到onSwiped()方法。默認是true,為了看起來清除,我們也把這個方法寫上
public boolean isItemViewSwipeEnabled() {
//該方法返回true時,表示如果用戶觸摸並且左滑了view,那么可以執行滑動刪除操作,就是可以調用onSwiped()方法
return true;
}
源代碼如下
public class myItemTouchHelperCallBack extends ItemTouchHelper.Callback{
private ItemTouchHelperAdapter itemTouchHelperAdapter;
private Context context;
private String title;
public myItemTouchHelperCallBack(ItemTouchHelperAdapter itemTouchHelperAdapter, Context context, String title) {
this.itemTouchHelperAdapter = itemTouchHelperAdapter;
this.context = context;
this.title = title;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//允許上下拖動
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
//允許從右向左滑動
int swipeFlags = ItemTouchHelper.LEFT;
return makeMovementFlags(dragFlags,swipeFlags);
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//onItemDelete接口里的方法
showCoverDialog(viewHolder);
}
@Override
public boolean isLongPressDragEnabled() {
//該方法返回值為true時,表示支持長按ItemView拖動
return false;
}
@Override
public boolean isItemViewSwipeEnabled() {
//該方法返回true時,表示如果用戶觸摸並且左滑了view,那么可以執行滑動刪除操作,就是可以調用onSwiped()方法
return true;
}
private void showCoverDialog(final RecyclerView.ViewHolder viewHolder){
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("提示");
builder.setMessage(title);
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
itemTouchHelperAdapter.onItemDelete(viewHolder.getAdapterPosition());
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
itemTouchHelperAdapter.onItemRefresh(viewHolder.getAdapterPosition());
}
});
builder.show();
}
}
4、在RecycleView中添加ItemTouchHelper
ItemTouchHelper.Callback callback = new myItemTouchHelperCallBack(adapter,context,"確定刪除此這篇收藏嗎?");
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(myCollectionList);
自此我們就實現了左滑刪除功能。
整個工程的代碼在github上可以查看