RecyclerView - 使用ItemTouchHelper实现侧滑删除效果
2021/12/12 23:19:29
本文主要是介绍RecyclerView - 使用ItemTouchHelper实现侧滑删除效果,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 前言
- 一、概述
- 二、了解ItemTouchHelper.Callback
- 三、如何实现
- 1.onChildDraw方法实现
- 2.clearView方法的实现:
- 3.效果显示
- 总结
前言
我们平时在QQ过程中,有一个效果是我们不可忽略的,那就是消息记录的侧滑删除功能。
一、概述
如上的效果是怎么实现之前,我们来看看上面效果都有那几个问题需要考虑的:
- 怎么实现左右侧滑?ItemTouchHelper?ItemTouchHelper怎么实现侧滑之后不删除,而是停留在某种状态上。
- 从上面的效果图中,我们可以明确的感受到左右滑动都可以超出RecyclerView的边界,只是在手指松开之后,ItemView会回到正确的位置而已。像这种overscroll效果应该怎么实现?
- 当停留在删除状态时,此时ItemView还可以从左右滑动(QQ只能向右滑动)。这种效果又应该怎么实现呢?
针对上面的三个问题,本文会详细的分析是怎么实现的。
二、了解ItemTouchHelper.Callback
我们知道,ItemTouchHelper的核心在于ItemTouchHelper.Callback接口中,所以在正式分析实现之前,我们先来了解temTouchHelper.Callback的几个方法。
方法名 | 作用 |
---|---|
getSwipeThreshold | 当 侧滑滑动的距离 / RecyclerView的宽大于该方法返回值,那么就会触发侧滑删除的操作。具体是:此时ItemView会做位移动画,当ItemView不可见时,会触发ItemTouchHelper的onSwiped方法,进而我们在onSwiped方法里面对Adapter进行remove操作。 |
getSwipeEscapeVelocity | 当侧滑的速度大于该方法的返回值,也会触发侧滑删除的操作。 |
onChildDraw | 此为核心方法,该方法在ItemView进行滑动时会回调,这里的滑动包括:1.手指滑动;2.ItemView的位移动画。可以根据isCurrentlyActive参数来判断是手指滑动还是动画滑动。 |
clearView | 为核心方法,该方法在ItemView滑动完成之后会回调,所以想要实现侧滑ItemView停在某种状态,此方法是核心之点。 |
经过对上面几个方法的理解,现在,我来简单描述一下效果的实现方法:
首先我们将滑动距离的阈值和滑动速度的阈值设置到最大,保证不会触发原本的侧滑删除操作。
当手指滑动时,我们就让它开心的滑动,不去怎么做任何的操作;当手指松开时,因为速度阈值和距离阈值都是最大,所以不可能超过它,那么ItemView会做动画回到最初的状态,但是我们不能按照原来的规则来位移ItemView,所以我们得判断手指松开那时ItemView的滑动距离是否大于我们设置的阈值(是否显示删除按钮的阈值),如果大于的话,那么就做动画到给定的位置就行,如果小于的话,就回到原始位置。
三、如何实现
现在我们正式来看一下代码,首先看一下getSwipeThreshold方法getSwipeEscapeVelocity方法:
代码如下(示例):
@Override public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { return Integer.MAX_VALUE; } @Override public float getSwipeEscapeVelocity(float defaultValue) { return Integer.MAX_VALUE; }
1.onChildDraw方法实现
我这里均设置为Integer.MAX_VALUE。其实getSwipeThreshold不用设置那么大,设置为1.1应该就行了,毕竟是百分比。
现在我们来看看onChildDraw方法的实现
代码如下(示例):
@Override public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { // 首次滑动时,记录下ItemView当前滑动的距离 if (dX == 0) { mCurrentScrollX = viewHolder.itemView.getScrollX(); mFirstInactive = true; } if (isCurrentlyActive) { // 手指滑动 // 基于当前的距离滑动 viewHolder.itemView.scrollTo(mCurrentScrollX + (int) -dX, 0); } else { // 动画滑动 if (mFirstInactive) { mFirstInactive = false; mCurrentScrollXWhenInactive = viewHolder.itemView.getScrollX(); mInitXWhenInactive = dX; } if (viewHolder.itemView.getScrollX() >= mDefaultScrollX) { // 当手指松开时,ItemView的滑动距离大于给定阈值,那么最终就停留在阈值,显示删除按钮。 viewHolder.itemView.scrollTo(Math.max(mCurrentScrollX + (int) -dX, mDefaultScrollX), 0); } else { // 这里只能做距离的比例缩放,因为回到最初位置必须得从当前位置开始,dx不一定与ItemView的滑动距离相等 viewHolder.itemView.scrollTo((int) (mCurrentScrollXWhenInactive * dX / mInitXWhenInactive), 0); } } }
需要注意的是,为了避免滑动时出现跳变,所以我们在手动时,必须基于当前的滑动距离来滑动,因为每一次手指滑动开始,dx都是从0开始的,这样就表示每一次手指滑动ItemView都从最初的位置开始滑动。
还需要注意一点,就是当手指停止滑动时,我们需要判断ItemView最终应该处于那种状态。这里说的状态无非是两种,一种是删除状态,一种最初状态。判断了状态之后,我们需要将ItemView位移到指定位置,这里两种方式:
- 自己实现动画,来滑动到指定位置。
- 通过onChildDraw方法的回调来滑动到指定位置。
2.clearView方法的实现:
这里我使用的是第二种方式,相对来说,第一种方式比较简单,毕竟是自己实现动画;而第二种方式需要dx的值。具体的细节大家可以看我代码上的注释。
我们再来看clearView方法的实现:
代码如下(示例):
@Override public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); if (viewHolder.itemView.getScrollX() > mDefaultScrollX) { viewHolder.itemView.scrollTo(mDefaultScrollX, 0); } else if (viewHolder.itemView.getScrollX() < 0) { viewHolder.itemView.scrollTo(0, 0); } mItemTouchStatus.onSaveItemStatus(viewHolder); }
clearView方法的作用就是当ItemView滑动完成之后,进行一些处理,这里我们必须保证ItemView滑动到指定位置,因为在计算过程中难免会有一点点误差,所以要进行归位处理。
3.效果显示
总结
本文部分参考了Android中RecyclerView部分的描述
参考文献
如果有疑问,欢迎大家在评论中给我留言,看到会及时回复。
作者:敖洋
这篇关于RecyclerView - 使用ItemTouchHelper实现侧滑删除效果的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享