深度解析RecyclerView:ItemTouchHelper实现拖拽与侧滑删除技巧

更新:10-28 民间故事 我要投稿 纠错 投诉

大家好,今天给各位分享深度解析RecyclerView:ItemTouchHelper实现拖拽与侧滑删除技巧的一些知识,其中也会对进行解释,文章篇幅可能偏长,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在就马上开始吧!

以上是官方文档的介绍。 ItemTouchHelper是一个可以实现侧滑删除和拖拽移动的工具类。使用这个工具类需要RecyclerView和Callback。还可以根据需要重写onMove 和onSwiped 方法。接下来我们就来说一下ItemTouchHelper的使用方法。

ItemTouchHelper基本使用方法

step.1新建一个接口,让Adapter实现之

从解耦的角度来说,我们需要一个接口来实现Adapter和ItemTouchHelper之间的数据相关操作,因为ItemTouchHelper在完成各种触摸动画之后必须对Adapter的数据进行操作,比如对于侧滑删除操作,您需要调用Adapter的notifyItemRemove()方法来删除数据。因此,我们可以将数据操作部分抽象为一个接口方法,让ItemTouchHelper.Callback调用该方法。详情如下:

创建新的ItemTouchHelperAdapter:

公共接口ItemTouchHelperAdapter {

//数据交换

void onItemMove(int fromPosition,int toPosition);

//数据删除

无效onItemDissmiss(int 位置);

让我们的适配器实现这个接口:

公共类MyAdapter 扩展RecyclerView.Adapterimplements ItemTouchHelperAdapter {

//数据

私有列表数据;

.

@覆盖

公共无效onItemMove(int fromPosition,int toPosition){

//交换位置

Collections.swap(mData,fromPosition,toPosition);

notificationItemMoved(fromPosition,toPosition);

}

@覆盖

公共无效onItemDissmiss(int位置){

//删除数据

mData.remove(位置);

通知项目已删除(位置);

}

然后我们就可以直接调用ItemTouchHelper.Callback中的接口方法了。

step.2新建类继承自ItemTouchHelper.Callback

从官方文档中我们知道使用ItemTouchHelper需要一个Callback,它是ItemTouchHelper.Callback的子类,所以我们需要创建一个新的类如SimpleItemTouchHelperCallback,它继承自ItemTouchHelper.Callback。我们可以重写它的几个方法来实现我们的需求。我们首先看一下ItemTouchHelper.Callback需要重写的一些常用方法。

1、public int getMovementFlags(RecyclerView, RecyclerView.ViewHolder):该方法用于返回滑动方向,比如允许从右向左滑动、允许上下拖动等。我们一般使用makeMovementFlags(int, int) 或makeFlag(int, int) 来构造我们的返回值。

例如:要使RecyclerView Item能够上下拖动,同时允许从右到左滑动,但不允许从左到右侧滑,我们可以这样写:

@覆盖

公共int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

int DragFlags=ItemTouchHelper.UP | ItemTouchHelper.DOWN; //允许上下拖动

int swipeFlags=ItemTouchHelper.LEFT; //只允许从右向左滑动

返回makeMovementFlags(dragFlags,swipeFlags);

}2、public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)当用户拖动一个Item从旧位置上下移动到新位置时会调用该方法。在这个方法中,我们可以调用Adapter的notifyItemMoved方法来交换两个ViewHolder的位置,最后返回true,表示被拖动的ViewHolder已经移动到了目标位置。因此,如果想实现拖动和交换位置,可以重写这个方法(前提是支持上下拖动):

@覆盖

公共布尔onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {

//onItemMove是一个接口方法

mAdapter.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());

返回真;

}3、public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)当用户向左或向右滑动item达到删除条件时,会调用该方法。一般情况下,当手指触摸和滑动距离达到RecyclerView宽度的一半时,然后松开手指。此时item会继续按原来的滑动方向滑动并调用onSwiped方法进行删除,否则会滑回原来的位置。在这个方法中我们可以这样写:

@覆盖

公共无效onSwiped(RecyclerView.ViewHolder viewHolder,int方向){

//onItemDissmiss是一个接口方法

mAdapter.onItemDissmiss(viewHolder.getAdapterPosition());

}如果我们在onSwiped方法内部不进行任何操作,即不删除已经滑过的Item,那么就会留下一个空白,因为ItemView实际上还占据着这个位置,只是刚刚移出了我们的位置视觉范围。就这样。

4、public boolean isLongPressDragEnabled():当该方法返回true时,表示支持长按拖动,即只有长按ItemView后才能进行拖动。我们一般都会遇到这样的场景。默认返回true。

5、public boolean boolean isItemViewSwipeEnabled():当该方法返回true时,表示如果用户触摸并向左或向右滑动View,则可以进行滑动删除操作,即可以调用onSwiped()方法。默认返回true。

6、public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState):从静态变为拖动或滑动时会回调该方法。参数actionState代表当前状态。

7、public void clearView(RecyclerView recyclerView, ViewHolder viewHolder):当用户操作完某个项目并且其动画结束时,将调用此方法。一般我们会在该方法中恢复ItemView的初始状态,防止复用造成显示混乱。

8、public void onChildDraw(...):我们可以在该方法中实现我们自定义的交互规则或者自定义动画效果。

那么完整的SimpleItemTouchHelperCallback文件是这样的:

公共类SimpleItemTouchHelperCallback 扩展ItemTouchHelper.Callback{

私有ItemTouchHelperAdapter mAdapter;

公共SimpleItemTouchHelperCallback(ItemTouchHelperAdapter 适配器){

mAdapter=适配器;

}

@覆盖

公共int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

int DragFlags=ItemTouchHelper.UP | ItemTouchHelper.DOWN;

int swipeFlags=ItemTouchHelper.LEFT;

返回makeMovementFlags(dragFlags,swipeFlags);

}

@覆盖

公共布尔isLongPressDragEnabled() {

返回真;

}

@覆盖

公共布尔isItemViewSwipeEnabled() {

返回真;

}

@覆盖

公共布尔onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {

mAdapter.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());

返回真;

}

@覆盖

公共无效onSwiped(RecyclerView.ViewHolder viewHolder,int方向){

mAdapter.onItemDissmiss(viewHolder.getAdapterPosition());

}

}

step.3为RecycleView添加ItemTouchHelper

上面我们修改了Adapter并创建了一个新的ItemTouchHelper.Callback子类。接下来我们需要将ItemTouchHelper 添加到RecyclerView 中:

//先实例化回调

ItemTouchHelper.Callback 回调=new SimpleItemTouchHelperCallback(myAdapter);

//使用Callback构造ItemtouchHelper

ItemTouchHelper touchHelper=new ItemTouchHelper(回调);

//调用ItemTouchHelper的attachToRecyclerView方法建立联系

touchHelper.attachToRecyclerView(mRecyclerView);经过以上步骤,我们就实现了Item的拖拽、滑动删除功能。看看效果:

拖动滑动.gif

自定义侧滑动画

有时我们可能对默认的动画效果不满意,需要自己实现想要的动画效果。 ItemTouchHelper.Callback提供的onChildDraw方法可以让我们轻松达到想要的效果。下面带来一个自定义实现效果作为切入点,让大家熟悉自定义效果的应用。我们先看一下要达到的效果:

定制侧滑.gif

这种效应比较常见。当用户向左滑动某项时,最初的提示是“向左滑动删除”。滑动到一定距离后,显示删除图标,并且随着滑动距离的增加,图标不断变大。达到最大值后,用户松开手指,该项目将被删除。

接下来我们来分析一下如何实现上述效果:

首先,如果你想向左滑动显示一个被删除的方块,你可以在LinearLayout中放置这样一个“方块”,并与Item并排水平排列。以下是布局文件:

?xml version="1.0"encoding="utf-8"?修改布局文件后,我们尝试滑动,发现后面的删除框并没有出现。这是因为默认的滑动方式是setTranslationX(int),即是对整个View的滑动,所以无论我们怎样滑动,都不会出现删除方块。。因此,我们需要改变滑动方式。比如使用scrollTo(int,int),这是View的内容的滑动,那么当你向左滑动时,item就会向左滑动,右边的方块自然就会出现。

接下来,我们考虑“删除眼睛”图标是如何从小到大的。这个实现比较简单。只需根据滑动距离改变ImageView的LayoutParams.width即可。但要注意限制大小,否则会太大。导致图像失真。当滑动距离等于RecyclerView宽度的一半时,此时松开手会导致Item被删除。那么当滑动距离达到这个值时我们就可以让“眼睛”最大。此时可以达到很好的交互效果,提示用户无需继续滑动来删除Item。

我们需要考虑的最后一件事是:删除Item 或将其滑回原始位置而不删除后,我们需要重置所做的更改。否则,由于RecyclerView的复用,其他位置的ViewHolder会和当前的不一样。 ViewHolder所做的改变是一样的,导致显示错误。我们可以在clearView()方法中重置变化,这样可以解决复用带来的显示问题。

最后我们看一下SimpleItemTouchHelperCallback的代码:

公共类SimpleItemTouchHelperCallback 扩展ItemTouchHelper.Callback{

//省略上面的代码.

//限制ImageView的长度可以增加的最大值

私有双ICON_MAX_SIZE=50;

//ImageView初始长宽

私有int 固定宽度=150;

@覆盖

公共无效clearView(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder){

super.clearView(recyclerView, viewHolder);

//重置更改,防止重用造成显示问题

viewHolder.itemView.setScrollX(0);

((MyAdapter.NormalItem)viewHolder).tv.setText("向左滑动删除");

FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) ((MyAdapter.NormalItem) viewHolder).iv.getLayoutParams();

参数宽度=150;

params.height=150;

((MyAdapter.NormalItem) viewHolder).iv.setLayoutParams(params);

((MyAdapter.NormalItem) viewHolder).iv.setVisibility(View.INVISIBLE);

}

@覆盖

公共无效onChildDraw(Canvas c,RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder,float dX,float dY,int actionState,boolean isCurrentlyActive){

//只对侧滑状态下的效果进行更改

if (actionState==ItemTouchHelper.ACTION_STATE_SWIPE){

//如果dX小于或等于被删除方块的宽度,那么我们将方块滑出

if (Math.abs(dX)=getSlideLimitation(viewHolder)){

viewHolder.itemView.scrollTo(-(int) dX,0);

}

//如果dX还没有达到可以删除的距离,此时慢慢增大“眼睛”的大小,最大增大为ICON_MAX_SIZE

否则if (Math.abs(dX)=recyclerView.getWidth()/2){

双倍距离=(recyclerView.getWidth()/2 -getSlideLimitation(viewHolder));

双因子=ICON_MAX_SIZE/距离;

双diff=(Math.abs(dX) - getSlideLimitation(viewHolder)) * 因子;

如果(差异=ICON_MAX_SIZE)

差异=ICON_MAX_SIZE;

((MyAdapter.NormalItem)viewHolder).tv.setText(""); //删除文本

((MyAdapter.NormalItem) viewHolder).iv.setVisibility(View.VISIBLE); //显示眼睛

FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) ((MyAdapter.NormalItem) viewHolder).iv.getLayoutParams();

params.width=(int) (fixWidth + diff);

params.height=(int) (fixWidth + diff);

((MyAdapter.NormalItem) viewHolder).iv.setLayoutParams(params);

}

}别的{

//拖动状态不发生变化,需要调用父类的方法

super.onChildDraw(c,recyclerView,viewHolder,dX,dY,actionState,isCurrentlyActive);

}

}

/**

* 获取被删除块的宽度

*/

公共int getSlideLimitation(RecyclerView.ViewHolder viewHolder){

ViewGroup viewGroup=(ViewGroup) viewHolder.itemView;

返回viewGroup.getChildAt(1).getLayoutParams().width;

}

}好了,至此,自定义效果的介绍就完成了。读者可以根据自己的需要实现不同的效果。最后,感谢您的阅读。如有错误,还请指出~

END,本文到此结束,如果可以帮助到大家,还望关注本站哦!

用户评论

哽咽

终于把RecyclerView弄明白了,还能拖拽删除,感觉真厉害!

    有20位网友表示赞同!

坠入深海i

ITEMTOUCHHELPER真心好用,以前一直用SwipeRefreshLayout,没想到还有更直接的方式弄删除效果。

    有9位网友表示赞同!

旧爱剩女

这篇文章正好解决我遇到的一块难题,原来可以这样实现拖拽和侧滑删除?太棒了!

    有15位网友表示赞同!

走过海棠暮

学习下ItemTouchHelper,之前只知道RecyclerView的基本用法,要多练习一下这种进阶功能。

    有12位网友表示赞同!

ok绷遮不住我颓废的伤あ

想要把页面弄得更交互一点,这个方法很值得尝试啊,上手难度应该不低吧?

    有20位网友表示赞同!

◆残留德花瓣

拖拽和侧滑删除确实是很实用的功能,现在很多APP都用上了,学习学习!

    有19位网友表示赞同!

箜篌引

看了这篇标题感觉很有意思,要好好学习一下 ItemTouchHelper 的用法。

    有18位网友表示赞同!

↘▂_倥絔

代码看起来复杂点,不过如果能成功实现的话肯定很酷!

    有9位网友表示赞同!

汐颜兮梦ヘ

拖拽和删除这些功能以前都用第三方库来解决,现在自己动手实现了真是牛逼!

    有7位网友表示赞同!

南宫沐风

这个进阶玩法真不错,以后可以试试给APP增加同样的功能。

    有11位网友表示赞同!

無極卍盜

RecyclerView 的学习之路越来越有趣了, 以后要多关注一些进阶教程。

    有18位网友表示赞同!

玻璃渣子

之前一直不知道 ItemTouchHelper 是用来干什么的,现在知道了!

    有6位网友表示赞同!

安陌醉生

这个标题看着好像很专业的样子,需要仔细阅读才能明白其中的知识点。

    有8位网友表示赞同!

巴黎盛开的樱花

学习一下ItemTouchHelper,以后项目中可以用到。

    有11位网友表示赞同!

身影

希望这篇文章能详细讲解 ItemTouchHelper 的使用方法,方便我参考学习。

    有17位网友表示赞同!

烟雨离殇

终于找到文章解释这个功能的方法了,之前一直迷茫!

    有10位网友表示赞同!

坏小子不坏

我想弄一个类似这种拖拽删除的界面,这篇标题应该有用的答案,就去看看~

    有9位网友表示赞同!

〆mè村姑

现在越来越多APP使用了这些交互式功能,看来要好好学习下 ItemTouchHelper 了。

    有15位网友表示赞同!

君临臣

我最近在学习RecyclerView,这篇文章好像很适合我。

    有10位网友表示赞同!

【深度解析RecyclerView:ItemTouchHelper实现拖拽与侧滑删除技巧】相关文章:

1.动物故事精选:寓教于乐的儿童故事宝库

2.《寓教于乐:精选动物故事助力儿童成长》

3.探索动物旅行的奇幻冒险:专为儿童打造的童话故事

4.《趣味动物刷牙小故事》

5.探索坚韧之旅:小蜗牛的勇敢冒险

6.传统风味烤小猪,美食探索之旅

7.探索奇幻故事:大熊的精彩篇章

8.狮子与猫咪的奇妙邂逅:一场跨界的友谊故事

9.揭秘情感的力量:如何影响我们的生活与决策

10.跨越两岸:探索彼此的独特世界

上一篇:高效构建SaaS应用的8个关键步骤指南 下一篇:《荒野猎人》:揭开其深层主题的探索之旅