RecyclerView 實現滑動刪除和拖拽功能
前言
從Android 5.0開始,谷歌推出了新的控制元件RecyclerView,相對於早它之前的ListView,優點多多,功能強大,也給我們的開發著提供了極大的便利,今天自己學習一下RecyclerView輕鬆實現滑動刪除及拖拽的效果,如下圖。
相信研究過RecyclerView的同學,應該很清楚該怎麼實現這樣的效果,若是用ListView,這樣的效果實現起來可能就有點麻煩,但是在強大的RecyclerView面前這樣的的效果只需很少的程式碼,因為谷歌給我們提供了強大的工具類ItemTouchHelper,它已經處理了關於RecyclerView拖動和滑動的實現,並且我們可以在其中實現我們自己的動畫,以及定製我們想要的效果。
ItemTouchHelper.Callback有幾個重要的抽象方法,我們繼承該抽象類,並重寫抽象方法。它是我們實現滑動和拖拽重要的回撥。
1 | intgetMovementFlags(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder |
該方法返回一個整數,用來指定拖拽和滑動在哪個方向是被允許的。在其中使用makeMovementFlags(int dragFlags, int swipeFlags)返回,該方法第一個引數用來指定拖動,第二個引數用來指定滑動。對於方向引數有6種
123456 | ItemTouchHelper.UP//滑動拖拽向上方向ItemTouchHelper.DOWN//向下ItemTouchHelper.LEFT//向左ItemTouchHelper.RIGHT//向右ItemTouchHelper.START//依賴佈局方向的水平開始方向ItemTouchHelper.END//依賴佈局方向的水平結束方向 |
1 | booleanonMove(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder,RecyclerView.ViewHolder target) |
onMove方法是拖拽的回撥,引數viewHolder是拖動的Item,target是拖動的目標位置的Item,該方法如果返回true表示切換了位置,反之返回false。
1 | voidonSwiped(RecyclerView.ViewHolder viewHolder,intdirection) |
onSwiped方法為Item滑動回撥,viewHolder為滑動的item,direction為滑動的方向。
上面三個方法是必須重寫的方法,當然還有其它一些可供選擇的方法。
12345678910111213141516171819202122232425262728293031323334 | /** * Item是否支援長按拖動 * * @return * true 支援長按操作 * false 不支援長按操作 */booleanisLongPressDragEnabled()/** * Item是否支援滑動 * * @return * true 支援滑動操作 * false 不支援滑動操作 */booleanisItemViewSwipeEnabled()/** * 移動過程中繪製Item * * @param c * @param recyclerView * @param viewHolder * @param dX * X軸移動的距離 * @param dY * Y軸移動的距離 * @param actionState * 當前Item的狀態 * @param isCurrentlyActive * 如果當前被使用者操作為true,反之為false */onChildDraw(Canvasc,RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder,floatdX,floatdY,intactionState,booleanisCurrentlyActive) |
需要注意的是,如果我們想實現拖動或者滑動必須將上面是否支援拖動或者滑動的方法返回true,否則onMove或者onSwiped方法不會執行。
功能實現
12345 | adapter=newCustomAdapter(getActivity(),strings);recycleview.setAdapter(adapter);ItemTouchHelper.Callback callback=newRecycleItemTouchHelper(adapter);ItemTouchHelper itemTouchHelper=newItemTouchHelper(callback);itemTouchHelper.attachToRecyclerView(recycleview); |
對於ItemTouchHelper 構造方法接收一個ItemTouchHelper.Callback引數,而這個Callback就是我們在在上述講到的工具類,初始化ItemTouchHelper 後通過其attachToRecyclerView(@Nullable RecyclerView recyclerView)方法將我們實現的ItemTouchHelper.Callback和RecyclerView關聯,最終達到我們的效果,程式碼看起來是不是很簡單,接下來我們看下我們自定義的Callback。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 | packagecom.example.xh.adapter;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.helper.ItemTouchHelper;import android.util.Log;import android.view.View;import com.example.xh.R;import com.example.xh.utils.MyApplication;/** * Created by xiehui on 2017/2/23. */publicclassRecycleItemTouchHelper extendsItemTouchHelper.Callback{privatestaticfinalStringTAG="RecycleItemTouchHelper";privatefinalItemTouchHelperCallback helperCallback;publicRecycleItemTouchHelper(ItemTouchHelperCallback helperCallback){this.helperCallback=helperCallback;}/** * 設定滑動型別標記 * * @param recyclerView * @param viewHolder * @return * 返回一個整數型別的標識,用於判斷Item那種移動行為是允許的 */@OverridepublicintgetMovementFlags(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder){Log.e(TAG,"getMovementFlags: ");//START 右向左 END左向右 LEFT 向左 RIGHT向右 UP向上//如果某個值傳0,表示不觸發該操作,次數設定支援上下拖拽,支援向右滑動returnmakeMovementFlags(ItemTouchHelper.UP|ItemTouchHelper.DOWN,ItemTouchHelper.END);}/** * Item是否支援長按拖動 * * @return * true 支援長按操作 * false 不支援長按操作 */@OverridepublicbooleanisLongPressDragEnabled(){returnsuper.isLongPressDragEnabled();}/** * Item是否支援滑動 * * @return * true 支援滑動操作 * false 不支援滑動操作 */@OverridepublicbooleanisItemViewSwipeEnabled(){returnsuper.isItemViewSwipeEnabled();}/** * 拖拽切換Item的回撥 * * @param recyclerView * @param viewHolder * @param target * @return * 如果Item切換了位置,返回true;反之,返回false */@OverridepublicbooleanonMove(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder,RecyclerView.ViewHolder target){Log.e(TAG,"onMove: ");helperCallback.onMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());returntrue;}/** * 滑動Item * * @param viewHolder * @param direction * Item滑動的方向 */@OverridepublicvoidonSwiped(RecyclerView.ViewHolder viewHolder,intdirection){Log.e(TAG,"onSwiped: ");helperCallback.onItemDelete(viewHolder.getAdapterPosition());}/** * Item被選中時候回撥 * * @param viewHolder * @param actionState * 當前Item的狀態 * ItemTouchHelper.ACTION_STATE_IDLE 閒置狀態 * ItemTouchHelper.ACTION_STATE_SWIPE 滑動中狀態 * ItemTouchHelper#ACTION_STATE_DRAG 拖拽中狀態 */@OverridepublicvoidonSelectedChanged(RecyclerView.ViewHolder viewHolder,intactionState){super.onSelectedChanged(viewHolder,actionState);}publicinterfaceItemTouchHelperCallback{voidonItemDelete(intpositon);voidonMove(intfromPosition,inttoPosition);}} |
在預設情況下是支援拖動和滑動的,也就是isLongPressDragEnabled()和isItemViewSwipeEnabled()是返回true的。在該類中我們建立了一個介面ItemTouchHelperCallback並建立兩個抽象方法,分別表示拖拽和滑動。在onMove方法中回撥建立我們建立的介面方法介面onMove(int fromPosition,int toPosition),並將拖拽和 Item 的posion和目標posion傳入,posion通過ViewHolder的getAdapterPosition()獲得,然後在滑動回撥方法onSwiped中回撥onItemDelete(int positon)。到這裡我們自定義的ItemTouchHelper.Callback建立完成。
上面完成後我們只需要在我們自定義的Adapter中實現RecycleItemTouchHelper.ItemTouchHelperCallback介面,然後在回撥方法中更新介面,如下Apdater中回撥方法實現。