使用RecylerView完成拖動排序高仿qq側(cè)滑刪除功能
最近使用到Recylerview完成拖動排序,側(cè)滑刪除,在此記錄一下。
需要使用到:ItemTouchHelper.Callback這個類。
效果圖:

在有RecylerView的Activity中,除了設(shè)置Adapter還需要做的事情有:
MyItemTouchHelperCallback callback = new MyItemTouchHelperCallback(adapter); //此類繼承ItemTouchHelper.Callback,這是幫助處理RecylerView拖動側(cè)滑操作的輔助類 ItemTouchHelper helper = new ItemTouchHelper(callback); //用上面實例化的callback實例化一個ItemTouchHelper對象。套路代碼,沒啥好說的,固定做法 helper.attachToRecyclerView(recyclerView); //讓help幫助處理recylerview的滑動,側(cè)滑操作
Activity中的操作就這么簡單。
接下來定義一個接口,這個接口是為了解除耦合,因為我看到有一些文章在activity中處理了onMove和onSwipe,抽象出來更好理解。
public interface OnMoveAndSwipeListener {
public boolean onItemMove(int fromPosition, int toPosition); //注意返回boolean哦
public void onItemDismiss(int position);
}
在RecylerView的Adapter中實現(xiàn)此接口,
復(fù)寫上面的兩個方法,
@Override
public boolean onItemMove(int fromPosition, int toPosition) {
if (fromPosition < toPosition) {
//往下移動時,做數(shù)據(jù)交換
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(list,i,i+1);
}
}else{
//往上移動,做數(shù)據(jù)交換
for (int i = fromPosition; i >toPosition ; i--) {
Collections.swap(list,i,i-1);
}
}
notifyItemMoved(fromPosition,toPosition);
return true;
}
@Override
public void onItemDismiss(int position) {
//此例沒有對側(cè)滑做操作,如果需要就在此模仿onItemMove方法,刪除對應(yīng)位置的數(shù)據(jù),并且刷新界面就可以了
}
這樣Adapter的工作也就完成了,一樣也很簡單,都有固定的套路,注意大家看到的demo都是有個默認的動畫,這個動畫效果是你在設(shè)置RecylerView時,recylerview.setItemAnimator(參數(shù));設(shè)置進去的,如果你沒有調(diào)用此方法,則就是默認動畫效果。
除了設(shè)置Adapter還需要做的事情有:
寫一個類繼承ItemTouchHelper.Callback,這就是最后一步了,也是本文最開始在Activity中實例化的類,
代碼也不多:
public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback {
MyAdapter adapter;
public MyItemTouchHelperCallback(MyAdapter adapter) {
this.adapter = adapter;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//復(fù)寫此方法用來設(shè)置我需要處理哪些操作
//我要處理上下拖動,就設(shè)置up down,如果是gridview類型的recylerview,up,down,left,right都可以處理
final int moveMode = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
//本例沒有處理側(cè)滑,如果需要處理側(cè)滑,就把注釋取消掉
//final int swipeMode = ItemTouchHelper.START | ItemTouchHelper.END;
Log.e("getMovementFlags","getMovementFlags");
return makeMovementFlags(moveMode, 0);//不處理什么,就傳0
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//當(dāng)你拖動時就會觸發(fā)此回調(diào),然后調(diào)用在adapter中復(fù)寫的onItemMove方法,去交換數(shù)據(jù)
return adapter.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//如果你要處理側(cè)滑就取消注釋,邏輯和上面的onMove一樣
// adapter.onItemDismiss(viewHolder.getAdapterPosition());
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
//此方法在你選中一個item拖動時觸發(fā),所以你可以在這里給選中的item設(shè)置一個背景色,用于高亮提示你選中了這個背景色
super.onSelectedChanged(viewHolder, actionState);
if (actionState!= ItemTouchHelper.ACTION_STATE_IDLE){
viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
}
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//因為你設(shè)置了背景色,所以在你不選中的時候,要取消掉這個背景色。
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setBackgroundColor(0);
}
}
到此為止,一個簡單的拖動和側(cè)滑就完成了,其實拖動和側(cè)滑的邏輯都是一樣的,按著上面的步驟來,效果就出來了。
上面只是一個簡單的效果。把上面的效果實現(xiàn)了,接下來看更進階一點的效果:
RecycleViewSwipeDismiss
要做到上述的效果,先說一下上面的邏輯:
首先他的每個Item的布局是兩層:
<?xml version="1.0" encoding="utf-8"?> <!--背景view,用于提示用戶操作結(jié)果--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/rl_background" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/iv_done" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="16dp" android:layout_marginStart="16dp" android:src="@mipmap/bt_ic_done_white_24" /> <ImageView android:id="@+id/iv_schedule" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:src="@mipmap/bt_ic_schedule_white_24" /> <!--滑動操作的view--> <LinearLayout android:id="@+id/ll_item" android:layout_width="match_parent" android:layout_height="64dp" android:background="@android:color/white" android:gravity="center_vertical" android:orientation="vertical" android:paddingLeft="16dp" android:paddingRight="16dp"> <TextView android:id="@+id/tv_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" tools:text="Item" /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_below="@id/ll_item" android:background="#B2B2b2" /> </RelativeLayout>
原理:全屏的linearlayout負責(zé)側(cè)滑效果,而根布局是有顏色有圖片的那一層,因為linearlayout被滑走了,所以根布局以及上面的圖片就出來了。
需要在MyItemTouchHelperCallback中重新復(fù)寫的幾個方法,以及多復(fù)寫的幾個方法:
<span style="white-space:pre"> </span> @Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// 釋放View時回調(diào),清除背景顏色,隱藏圖標
// 默認是操作ViewHolder的itemView,這里調(diào)用ItemTouchUIUtil的clearView方法傳入指定的view
getDefaultUIUtil().clearView(((SampleAdapter.ItemViewHolder) viewHolder).vItem);
((SampleAdapter.ItemViewHolder) viewHolder).vBackground.setBackgroundColor(Color.TRANSPARENT);
((SampleAdapter.ItemViewHolder) viewHolder).ivSchedule.setVisibility(View.GONE);
((SampleAdapter.ItemViewHolder) viewHolder).ivDone.setVisibility(View.GONE);
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// 當(dāng)viewHolder的滑動或拖拽狀態(tài)改變時回調(diào)
if (viewHolder != null) {
// 默認是操作ViewHolder的itemView,這里調(diào)用ItemTouchUIUtil的clearView方法傳入指定的view
getDefaultUIUtil().onSelected(((SampleAdapter.ItemViewHolder) viewHolder).vItem);
}
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
// ItemTouchHelper的onDraw方法會調(diào)用該方法,可以使用Canvas對象進行繪制,繪制的圖案會在RecyclerView的下方
// 默認是操作ViewHolder的itemView,這里調(diào)用ItemTouchUIUtil的clearView方法傳入指定的view
getDefaultUIUtil().onDraw(c, recyclerView, ((SampleAdapter.ItemViewHolder) viewHolder).vItem, dX, dY, actionState, isCurrentlyActive);
if (dX > 0) { // 向左滑動是的提示
((SampleAdapter.ItemViewHolder) viewHolder).vBackground.setBackgroundResource(R.color.colorDone);
((SampleAdapter.ItemViewHolder) viewHolder).ivDone.setVisibility(View.VISIBLE);
((SampleAdapter.ItemViewHolder) viewHolder).ivSchedule.setVisibility(View.GONE);
}
if (dX < 0) { // 向右滑動時的提示
((SampleAdapter.ItemViewHolder) viewHolder).vBackground.setBackgroundResource(R.color.colorSchedule);
((SampleAdapter.ItemViewHolder) viewHolder).ivSchedule.setVisibility(View.VISIBLE);
((SampleAdapter.ItemViewHolder) viewHolder).ivDone.setVisibility(View.GONE);
}
}
@Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
// ItemTouchHelper的onDrawOver方法會調(diào)用該方法,可以使用Canvas對象進行繪制,繪制的圖案會在RecyclerView的上方
// 默認是操作ViewHolder的itemView,這里調(diào)用ItemTouchUIUtil的clearView方法傳入指定的view
getDefaultUIUtil().onDrawOver(c, recyclerView, ((SampleAdapter.ItemViewHolder) viewHolder).vItem, dX, dY, actionState, isCurrentlyActive);
}
});
用getDefaultUIUtil()的方法指定滑動操作的是linearlayout,所以每次被滑走的只有l(wèi)inearlayout。其他的操作都是一樣的。
相關(guān)文章
Android BroadcastReceiver廣播注冊方式總結(jié)
這篇文章主要介紹了Android BroadcastReceiver廣播注冊方式總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-01-01
Jetpack?Compose實現(xiàn)點擊事件click的多種方法
這篇文章主要介紹了Jetpack?Compose實現(xiàn)點擊事件的多種方法,Jetpack?Compose是一款基于Kotlin的聲明式UI工具包,可以方便地創(chuàng)建漂亮的用戶界面,下面我們就來看看Jetpack?Compose添加點擊事件都可以怎么實現(xiàn)2024-02-02
Android studio虛擬機在啟動界面和桌面出現(xiàn)畫面模糊花屏問題的解決方法
這篇文章主要介紹了解決Android studio虛擬機在啟動界面和桌面出現(xiàn)畫面模糊花屏問題,本文通過圖文并茂的形式給大家介紹的非常詳細,需要的朋友可以參考下2020-03-03
Android中協(xié)調(diào)滾動布局的實現(xiàn)代碼
這篇文章主要介紹了Android中協(xié)調(diào)滾動常用的布局實現(xiàn),類似這樣的協(xié)調(diào)滾動布局,當(dāng)?shù)撞苛斜砘瑒拥臅r候,頂部的布局做響應(yīng)的動作,我們都可以通過?AppBarLayout?和?MotionLayout?來實現(xiàn),本文通過實例代碼介紹的非常詳細,需要的朋友參考下吧2022-06-06
Android實現(xiàn)Back功能代碼片段總結(jié)
今天把在公司實現(xiàn)某功能所用到的Back鍵功能模塊代碼片段做一個整理。方便以后直接拿出來使用2014-09-09

