ItemTouchHelper是RecyclerView高級(jí)篇的重要知識(shí)之一,它可以實(shí)現(xiàn)Item的拖拽以及側(cè)滑刪除。
先來(lái)看一下效果,如下:

在了解效果的前提下,我將一步步剖析其實(shí)現(xiàn)原理。
(1)基本使用
我們首先需要了解,ItemTouchHelper如何使用,看以下代碼
//聲明一個(gè)Callback
ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
//返回方向值
return 0;
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
//拖拽處理
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
//滑動(dòng)處理
}
};
//創(chuàng)建helper對(duì)象
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
//關(guān)聯(lián)recyclerView
itemTouchHelper.attachToRecyclerView(recyclerview);
或者
//聲明一個(gè)Callback
ItemTouchHelper.Callback callback = new ItemTouchHelper.SimpleCallback(dragDirs, swipeDirs) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
//拖拽處理
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
//滑動(dòng)處理
}
};
//創(chuàng)建helper對(duì)象
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
//關(guān)聯(lián)recyclerView
itemTouchHelper.attachToRecyclerView(recyclerview);
attachToRecyclerView方法理解起來(lái)比較簡(jiǎn)單,就是將RecyclerView與ItemTouchHelper進(jìn)行關(guān)聯(lián),唯一不清楚的是,Callback中的三個(gè)方法沒(méi)有任何的業(yè)務(wù)邏輯,我們必須在這三個(gè)方法中處理這三個(gè)方法的業(yè)務(wù)邏輯,如果不處理,那么ItemTouchHelper則無(wú)任何效果。
在實(shí)現(xiàn)Callback內(nèi)部三個(gè)方法業(yè)務(wù)邏輯之前,我們需要了解這三個(gè)方法分別代表的意義:
- getMovementFlags:移動(dòng)標(biāo)志;
- onMove:拖拽的處理
- onSwiped:滑動(dòng)的處理
(2)getMovementFlags: 獲取移動(dòng)狀態(tài)
ItemTouchHelper幫助類(lèi)自帶創(chuàng)建移動(dòng)標(biāo)志的方法,如下代碼:
/**
* Convenience method to create movement flags.
* <p>
* For instance, if you want to let your items be drag & dropped vertically and swiped
* left to be dismissed, you can call this method with:
* <code>makeMovementFlags(UP | DOWN, LEFT);</code>
*
* @param dragFlags The directions in which the item can be dragged.
* @param swipeFlags The directions in which the item can be swiped.
* @return Returns an integer composed of the given drag and swipe flags.
*/
public static int makeMovementFlags(int dragFlags, int swipeFlags) {
return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags)
| makeFlag(ACTION_STATE_SWIPE, swipeFlags)
| makeFlag(ACTION_STATE_DRAG, dragFlags);
}
dragFlags表示拖拽方向標(biāo)志,swipeFlags表示滑動(dòng)方向標(biāo)志,這個(gè)標(biāo)志可以理解為一種狀態(tài),那么這兩個(gè)值傳遞怎樣的參數(shù)呢?
//控制拖拽的方向(一般是上下左右)
int dragFlags= ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//控制快速滑動(dòng)的方向(一般是左右)
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
我們看一下以上代碼,假設(shè):
dragFlags被賦予上下左右四個(gè)方向狀態(tài),所以拖拽方向狀態(tài)為:上、下、左、右
swipeFlags 被賦予左右兩個(gè)方向狀態(tài),所以滑動(dòng)方向狀態(tài)為:左、右
將拖拽方向狀態(tài)dragFlags以及滑動(dòng)方向狀態(tài)swipeFlags傳遞到makeMovementFlags方法中,接著看一下makeFlag這個(gè)方法:
/**
* Shifts the given direction flags to the offset of the given action state.
*
* @param actionState The action state you want to get flags in. Should be one of
* {@link #ACTION_STATE_IDLE}, {@link #ACTION_STATE_SWIPE} or
* {@link #ACTION_STATE_DRAG}.
* @param directions The direction flags. Can be composed from {@link #UP}, {@link #DOWN},
* {@link #RIGHT}, {@link #LEFT} {@link #START} and {@link #END}.
* @return And integer that represents the given directions in the provided actionState.
*/
@SuppressWarnings("WeakerAccess")
public static int makeFlag(int actionState, int directions) {
return directions << (actionState * DIRECTION_FLAG_COUNT);
}
這個(gè)方法最后的返回值為三種狀態(tài):無(wú)操作狀態(tài)、拖拽狀態(tài)、滑動(dòng)狀態(tài)(注意和拖拽方向狀態(tài)、滑動(dòng)方向狀態(tài)區(qū)別開(kāi)),最終makeMovementFlags的返回值為:
return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags)
| makeFlag(ACTION_STATE_SWIPE, swipeFlags)
| makeFlag(ACTION_STATE_DRAG, dragFlags);
將無(wú)操作狀態(tài)、滑動(dòng)狀態(tài)、拖拽狀態(tài)合并為移動(dòng)狀態(tài)。
以上所述的狀態(tài)優(yōu)點(diǎn)多,您可能會(huì)被繞暈,所以專(zhuān)門(mén)為大家繪制了一個(gè)思維導(dǎo)圖:

如圖所示,起初通過(guò)上下左右這四個(gè)方向狀態(tài),一步一步的轉(zhuǎn)變?yōu)橐苿?dòng)狀態(tài)。
如果您使用SimpleCallback內(nèi)部類(lèi),在內(nèi)部有一個(gè)方法如下:
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView,
@NonNull ViewHolder viewHolder) {
return makeMovementFlags(getDragDirs(recyclerView, viewHolder),
getSwipeDirs(recyclerView, viewHolder));
}
這個(gè)方法表明,使用SimpleCallback內(nèi)部類(lèi)不需要重寫(xiě)getMovementFlags方法,只需要傳遞dragDirs, swipeDirs這兩個(gè)參數(shù)即可,其實(shí)和Callback內(nèi)部類(lèi)差不多,如果使用Callback內(nèi)部類(lèi),那么getMovementFlags完善后的代碼如下:
//聲明一個(gè)Callback
ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
//控制拖拽的方向(一般是上下左右)
int dragFlags= ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//控制快速滑動(dòng)的方向(一般是左右)
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
return makeMovementFlags(dragFlags, swipeFlags);//計(jì)算movement flag值
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
//拖拽處理
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
//滑動(dòng)處理
}
};
就這樣,getMovementFlags方法已經(jīng)實(shí)現(xiàn)完成,代碼的意思是:在拖拽時(shí),允許Item上、下、左、右四個(gè)方向拖拽,在滑動(dòng)時(shí),允許Item左、右兩個(gè)方向滑動(dòng)。
當(dāng)然,如果您只想讓Item向左滑動(dòng),那么將以下代碼
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
改成
int swipeFlags = ItemTouchHelper.LEFT;
或者
//控制快速滑動(dòng)的方向(一般是左右)
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//排除右方向
swipeFlags &=~ItemTouchHelper.RIGHT;
即可。
有關(guān)添加狀態(tài)和移除狀態(tài)相關(guān)算法我補(bǔ)充一下吧,雖然不是文章的重點(diǎn)(其實(shí),我怕您看不懂)
- 使用
按位或添加狀態(tài),如:
flag |= ItemTouchHelper.RIGHT
- 使用
按位與和按位非移除狀態(tài),如:
flag &= ~ItemTouchHelper.RIGHT
(3)onMove: 拖拽處理
方法如下:
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
//拖拽處理
return true;
}
這個(gè)方法是有返回值的,true:允許拖拽 false:禁止拖拽
假設(shè),有一個(gè)需求,將Item拖拽到某個(gè)位置,并和當(dāng)前位置的Item交換位置,這個(gè)該怎么做呢?
這個(gè)需求的處理,可以在onMove方法中處理,因?yàn)樗娜齻€(gè)參數(shù)recyclerView、viewHolder、target為這個(gè)需求提供了一切前提,viewHolder是被拖拽的Item,target是目標(biāo)Item,只需要將viewHolder和target交換位置就可以實(shí)現(xiàn)這個(gè)需求,代碼實(shí)現(xiàn)也比較簡(jiǎn)單,如下:
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
// 拖拽時(shí),每移動(dòng)一個(gè)位置就會(huì)調(diào)用一次。
if (recyclerView == null){
return false;
}
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter == null){
return false;
}
if (list != null && list.size() > 0) {
//獲取被拖拽的Item的Position
int from = viewHolder.getAdapterPosition();
//獲取目標(biāo)Item的Position
int endPosition = target.getAdapterPosition();
//交換List集合中兩個(gè)元素的位置
Collections.swap(list, from, endPosition);
//交換界面上兩個(gè)Item的位置
adapter.notifyItemMoved(from, endPosition);
}
return true;
}
效果如下:

(4)onSwiped: 滑動(dòng)處理
onSwiped是為了實(shí)現(xiàn)Item的左右滑動(dòng),由于我在getMovementFlags方法中已經(jīng)允許讓Item左右側(cè)滑,所以此時(shí)Item是只吃左右滑動(dòng)的,效果如下:

如圖所示,在界面刪Item已經(jīng)被刪除,但是,您知道的,List數(shù)據(jù)對(duì)應(yīng)的數(shù)據(jù)沒(méi)有被刪除,而且屏幕上顯示的RecyclerView沒(méi)有被刷新,這些處理需要在onSwiped方法中處理,代碼如下:
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
//滑動(dòng)處理
int position = viewHolder.getAdapterPosition();
if(list != null && list.size() > 0){
//刪除List中對(duì)應(yīng)的數(shù)據(jù)
list.remove(position);
if (recycleViewAdapter == null){
return;
}
//刷新頁(yè)面
recycleViewAdapter.notifyItemRemoved(position);
}
}
};
效果如下:

(5)getMoveThreshold: 設(shè)置拖拽距離百分比
看一下以下方法:
@Override
public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
return .5f;
}
如果RecyclerView是垂直方向,那么當(dāng)拖拽到當(dāng)前Item高度的50%時(shí)開(kāi)始執(zhí)行onMove方法。
下面我將貼出兩張圖,分別表示0.5和5的情況:
返回值為0.5的情況:

返回值為4的情況:

(6)getMoveThreshold: 設(shè)置拖拽距離百分比
@Override
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
//返回值滑動(dòng)消失的距離, 這里是相對(duì)于RecycleView的寬度,0.5f表示為RecycleView的寬度的一半,取值為0~1f之間
return .5f;
}
它的返回值默認(rèn)為50%,一般沒(méi)有特殊需求就按照默認(rèn)。
(7)getSwipeEscapeVelocity: 精確的計(jì)算出滑動(dòng)消失的距離
@Override
public float getSwipeEscapeVelocity(float defaultValue) {
//返回值滑動(dòng)消失的距離,滑動(dòng)小于這個(gè)值不消失,大于消失,默認(rèn)為屏幕的三分之一
//defaultValue默認(rèn)值為120dp,轉(zhuǎn)成px為 defaultValue * density
return defaultValue;
}
defaultValue默認(rèn)值為120dp,轉(zhuǎn)成px為defaultValue * density(density為像素縮放因子)
(8)getSwipeVelocityThreshold: 控制慣性速率
@Override
public float getSwipeVelocityThreshold(float defaultValue) {
//設(shè)置滑動(dòng)速率,這里的速率是指以一定的速率滑動(dòng)Item,松開(kāi)時(shí)Item依然從某一個(gè)方向移動(dòng)的速率(可以理解為慣性的速率)
//defaultValue默認(rèn)值為800dp,轉(zhuǎn)成px為 defaultValue * density
return defaultValue;
}
defaultValue默認(rèn)值為800dp,轉(zhuǎn)成px為 defaultValue * density(density為像素縮放因子)
(9)isLongPressDragEnabled: 是否允許長(zhǎng)按拖拽
@Override
public boolean isLongPressDragEnabled() {
return true;
}
它的返回值默認(rèn)為true。
(10)isItemViewSwipeEnabled: 是否允許左右滑動(dòng)刪除
@Override
public boolean isItemViewSwipeEnabled() {
return true
}
它的返回值默認(rèn)為true。
(11)onSelectedChanged: 拖拽或滑動(dòng)時(shí)被調(diào)用
@Override
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
}
從靜止?fàn)顟B(tài)變?yōu)橥献Щ蛘呋瑒?dòng)的時(shí)候會(huì)回調(diào)該方法,參數(shù)actionState表示當(dāng)前的狀態(tài)。
這個(gè)方法可以用于處理在拖拽或者滑動(dòng)時(shí)的UI變化。
(12)getAnimationDuration: 設(shè)置動(dòng)畫(huà)時(shí)間
@Override
public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
}
當(dāng)手指松開(kāi)時(shí),Item會(huì)移動(dòng)到某個(gè)固定的位置,這個(gè)動(dòng)作就是Item動(dòng)畫(huà),而getAnimationDuration方法可以設(shè)置動(dòng)畫(huà)的時(shí)間,默認(rèn)為200ms或者250ms。
(13)clearView: 初始化話(huà),清空View的狀態(tài)
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
}
當(dāng)拖拽或滑動(dòng)動(dòng)畫(huà)結(jié)束時(shí),也就是手指松開(kāi)并等待動(dòng)畫(huà)結(jié)束時(shí)會(huì)執(zhí)行clearView方法,這個(gè)方法可以用來(lái)初始化數(shù)據(jù)。
(14)onChildDraw: 在Item底部繪制圖形
@Override
public void onChildDraw(@NonNull Canvas canvas, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
onChildDraw方法有如下幾個(gè)參數(shù):
- canvas: 畫(huà)布,可以用于繪制圖形
- recyclerView:RecyclerView對(duì)象
- viewHolder:被操作的Item
- dX:Item被操作時(shí)的X軸方向的偏移量
- dY:Item被操作時(shí)的Y軸方向的偏移量
- actionState:移動(dòng)狀態(tài),在前文已經(jīng)給出移動(dòng)的三種狀態(tài):
無(wú)操作狀態(tài)、拖拽狀態(tài)、滑動(dòng)狀態(tài) - isCurrentlyActive:滑動(dòng)分為兩類(lèi)。其一:手指滑動(dòng);其二:Item位移動(dòng)畫(huà)滑動(dòng);isCurrentlyActive可以用于判斷是哪種滑動(dòng),如果isCurrentlyActive為true則表示手指滑動(dòng)
我們看一下以下代碼
private Paint paint;
private RectF rect;
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
//Item底部底部繪制圖形
c.translate(-dX, 0);
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
//在布局中,我設(shè)置的是4dp,這里需要轉(zhuǎn)成px
float padding = 4 * getResources().getDisplayMetrics().density + 0.5f;
//獲取X軸Item位置
float x = viewHolder.itemView.getX() + padding;
float y = viewHolder.itemView.getY() + padding;
float width = viewHolder.itemView.getWidth() - 2 * padding;
float height = viewHolder.itemView.getHeight() - 2 * padding;
rect = new RectF(x, y, x + width, y + height);
c.drawRect(rect, paint);
}
代碼的意思也很簡(jiǎn)單,就是使用Canvas繪制一個(gè)矩形,演示效果如下:

(15)onChildDrawOver: 在Item上面繪制圖形
@Override
public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
onChildDrawOver方法有如下幾個(gè)參數(shù):
- canvas: 畫(huà)布,可以用于繪制圖形
- recyclerView:RecyclerView對(duì)象
- viewHolder:被操作的Item
- dX:Item被操作時(shí)的X軸方向的偏移量
- dY:Item被操作時(shí)的Y軸方向的偏移量
- actionState:移動(dòng)狀態(tài),在前文已經(jīng)給出移動(dòng)的三種狀態(tài):
無(wú)操作狀態(tài)、拖拽狀態(tài)、滑動(dòng)狀態(tài) - isCurrentlyActive:滑動(dòng)分為兩類(lèi)。其一:手指滑動(dòng);其二:Item位移動(dòng)畫(huà)滑動(dòng);isCurrentlyActive可以用于判斷是哪種滑動(dòng),如果isCurrentlyActive為true則表示手指滑動(dòng)
我們看一下以下代碼
@Override
public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
//Item上面繪制圖形
//c.translate(-dX, 0);
paint = new Paint();
paint.setColor(Color.GRAY);
paint.setStyle(Paint.Style.FILL);
//在布局中,我設(shè)置的是4dp,這里需要轉(zhuǎn)成px
float padding = 4 * getResources().getDisplayMetrics().density + 0.5f;
//獲取X軸Item位置
float x = viewHolder.itemView.getX() + padding;
float y = viewHolder.itemView.getY() + padding;
float width = viewHolder.itemView.getWidth() - 2 * padding;
float height = viewHolder.itemView.getHeight() - 2 * padding;
rect = new RectF(x + width - 200, y + height / 2 - 50, x + width - 100, y + height / 2 + 50);
c.drawRect(rect, paint);
}
上面代碼的意思是:在Item上面畫(huà)一個(gè)正方形。
效果圖如下:

圖中可以看到,Item上已經(jīng)繪制了一個(gè)正方形。
(16)完整代碼
//聲明一個(gè)Callback
ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
//控制拖拽的方向(一般是上下左右)
int dragFlags= ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//控制快速滑動(dòng)的方向(一般是左右)
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
return makeMovementFlags(dragFlags, swipeFlags);//計(jì)算movement flag值
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
// 拖拽時(shí),每移動(dòng)一個(gè)位置就會(huì)調(diào)用一次。
if (recyclerView == null){
return false;
}
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter == null){
return false;
}
if (list != null && list.size() > 0) {
//獲取被拖拽的Item的Position
int from = viewHolder.getAdapterPosition();
//獲取目標(biāo)Item的Position
int endPosition = target.getAdapterPosition();
//交換List集合中兩個(gè)元素的位置
Collections.swap(list, from, endPosition);
//交換界面上兩個(gè)Item的位置
adapter.notifyItemMoved(from, endPosition);
}
return true;
}
@Override
public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
//設(shè)置拖拽距離百分比
//如果RecyclerView是垂直方向,那么當(dāng)拖拽到當(dāng)前Item高度的50%時(shí)開(kāi)始執(zhí)行onMove方法
return .5f;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
//滑動(dòng)處理
int position = viewHolder.getAdapterPosition();
if(list != null && list.size() > 0){
//刪除List中對(duì)應(yīng)的數(shù)據(jù)
list.remove(position);
if (recycleViewAdapter == null){
return;
}
//刷新頁(yè)面
recycleViewAdapter.notifyItemRemoved(position);
}
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
@Override
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
}
private Paint paint;
private RectF rect;
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
//Item底部底部繪制圖形
c.translate(-dX, 0);
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
//在布局中,我設(shè)置的是4dp,這里需要轉(zhuǎn)成px
float padding = 4 * getResources().getDisplayMetrics().density + 0.5f;
//獲取X軸Item位置
float x = viewHolder.itemView.getX() + padding;
float y = viewHolder.itemView.getY() + padding;
float width = viewHolder.itemView.getWidth() - 2 * padding;
float height = viewHolder.itemView.getHeight() - 2 * padding;
rect = new RectF(x, y, x + width, y + height);
c.drawRect(rect, paint);
}
@Override
public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
return 1000;
}
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
}
@Override
public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
//Item上面繪制圖形
//c.translate(-dX, 0);
paint = new Paint();
paint.setColor(Color.GRAY);
paint.setStyle(Paint.Style.FILL);
//在布局中,我設(shè)置的是4dp,這里需要轉(zhuǎn)成px
float padding = 4 * getResources().getDisplayMetrics().density + 0.5f;
//獲取X軸Item位置
float x = viewHolder.itemView.getX() + padding;
float y = viewHolder.itemView.getY() + padding;
float width = viewHolder.itemView.getWidth() - 2 * padding;
float height = viewHolder.itemView.getHeight() - 2 * padding;
rect = new RectF(x + width - 200, y + height / 2 - 50, x + width - 100, y + height / 2 + 50);
c.drawRect(rect, paint);
}
@Override
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
//返回值滑動(dòng)消失的距離, 這里是相對(duì)于RecycleView的寬度,0.5f表示為RecycleView的寬度的一半,取值為0~1f之間
return .5f;
}
@Override
public float getSwipeEscapeVelocity(float defaultValue) {
//返回值滑動(dòng)消失的距離,滑動(dòng)小于這個(gè)值不消失,大于消失,默認(rèn)為屏幕的三分之一
//defaultValue默認(rèn)值為120dp,轉(zhuǎn)成px為 defaultValue * density
return defaultValue;
}
@Override
public float getSwipeVelocityThreshold(float defaultValue) {
//設(shè)置滑動(dòng)速率,這里的速率是指以一定的速率滑動(dòng)Item,松開(kāi)時(shí)Item依然從某一個(gè)方向移動(dòng)的速率(可以理解為慣性的速率)
//defaultValue默認(rèn)值為800dp,轉(zhuǎn)成px為 defaultValue * density
return defaultValue;
}
};
//創(chuàng)建helper對(duì)象
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
//關(guān)聯(lián)recyclerView
itemTouchHelper.attachToRecyclerView(recyclerview);
以上代碼只要演示一遍,基本就會(huì)明白ItemTouchHelper的作用,ItemTouchHelper常用方法是getMovementFlags、onMove、onSwiped,強(qiáng)烈建議重點(diǎn)學(xué)習(xí)。
[本章完...]