RecyclerView的强大之处就不用多说了,谁用谁知道哦,本着学习的态度我们来给RecyclerView加上侧滑删除Item的功能,话不多说,先看图:

ItemRemoveRecyclerView

Gif效果不够理想,呜呜......

其实核心思想很简单,就是通过重写RecyclerView的onTouchEvent()方法来检测手势的变化实现的,大致的流程如下:

1、根据手指触摸的坐标点找到对应Item的ViewHolder,进而得到相应的Item布局View。

2、手指继续移动,在条件满足的情况下,通过scrollBy()使Item布局View内容跟随手指一起移动,当然要注意边界检测。

3、手指抬起时,根据Item布局View内容移动的距离以及手指的滑动速度,判断是否显示删除按钮,进而通过startScroll()使Item布局View自动滑动到目标位置。

4、点击删除按钮则删除对应Item,点击其它区域则隐藏删除按钮。

由于Item的侧滑删除效果需要通过Scroller辅助实现的,还不了解Scroller的同学可以看下这篇文章:Android Scroller实现View弹性滑动完全解析。

接下来看一下具体的实现过程:

先看一下onTouchEvent的MotionEvent.ACTION_DOWN事件处理:

public boolean onTouchEvent(MotionEvent e) {

mVelocityTracker.addMovement(e);

int x = (int) e.getX();

int y = (int) e.getY();

switch (e.getAction()) {

case MotionEvent.ACTION_DOWN:

if (mDeleteBtnState == 0) {

View view = findChildViewUnder(x, y);

if (view == null) {

return false;

}

MyViewHolder viewHolder = (MyViewHolder) getChildViewHolder(view);

mItemLayout = viewHolder.layout;

mPosition = viewHolder.getAdapterPosition();

mDelete = (TextView) mItemLayout.findViewById(R.id.item_delete);

mMaxLength = mDelete.getWidth();

mDelete.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

mListener.onDeleteClick(mPosition);

mItemLayout.scrollTo(0, 0);

mDeleteBtnState = 0;

}

});

} else if (mDeleteBtnState == 3) {

mScroller.startScroll(mItemLayout.getScrollX(), 0, -mMaxLength, 0, 200);

invalidate();

mDeleteBtnState = 0;

return false;

} else {

return false;

}

break;

case MotionEvent.ACTION_MOVE:

break;

case MotionEvent.ACTION_UP:

break;

}

mLastX = x;

mLastY = y;

return super.onTouchEvent(e);

}

我们规定删除按钮有四个状态(mDeleteBtnState):0:关闭,1:将要关闭,2:将要打开,3:打开

当删除按钮未展示时,即if (mDeleteBtnState == 0)时,通过findChildViewUnder()方法得到触摸点对应的Item View,接下来通过getChildViewHolder()得到对应的ViewHolder,有了ViewHolder,我们就可以解析出Item的布局mItemLayout以及当前Item的下标mPosition,最后得到mMaxLength ,即删除按钮的宽度也就是Item的最大滑动距离,同时给删除按钮绑定事件。

当else if (mDeleteBtnState == 3)时,Item上的删除按钮完全展示,如果点击删除按钮外的任意区域则通过startScroll()方法使Item自动右滑直到删除按钮完全隐藏,并且onTouchEvent()方法返回flase,这样此次事件结束,不会继续传递。

如果前两个条件都不满足,表示上一次Item的滑动操作尚未结束,则直接返回false,保证上一次的滑动操作顺利完成。

onTouchEvent的MotionEvent.ACTION_MOVE事件处理代码如下:

public boolean onTouchEvent(MotionEvent e) {

mVelocityTracker.addMovement(e);

int x = (int) e.getX();

int y = (int) e.getY();

switch (e.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

int dx = mLastX - x;

int dy = mLastY - y;

int scrollX = mItemLayout.getScrollX();

if (Math.abs(dx) > Math.abs(dy)) {

isItemMoving = true;

if (scrollX + dx <= 0) {//左边界检测

mItemLayout.scrollTo(0, 0);

return true;

} else if (scrollX + dx >= mMaxLength) {//右边界检测

mItemLayout.scrollTo(mMaxLength, 0);

return true;

}

mItemLayout.scrollBy(dx, 0);//item跟随手指滑动

}

break;

case MotionEvent.ACTION_UP:

break;

}

mLastX = x;

mLastY = y;

return super.onTouchEvent(e);

}

当手指滑动的时候,如果水平滑动距离大于垂直滑动距离,则通过scrollBy()方法使Item可跟随手指左右滑动,当然我们进行了滑动的边界检测,并不会出现滑动越界的情况哦!

最后看一下onTouchEvent的MotionEvent.ACTION_UP事件处理:

public boolean onTouchEvent(MotionEvent e) {

mVelocityTracker.addMovement(e);

int x = (int) e.getX();

int y = (int) e.getY();

switch (e.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

break;

case MotionEvent.ACTION_UP:

if (!isItemMoving && !isDragging && mListener != null) {

mListener.onItemClick(mItemLayout, mPosition);

}

isItemMoving = false;

mVelocityTracker.computeCurrentVelocity(1000);//计算手指滑动的速度

float xVelocity = mVelocityTracker.getXVelocity();//水平方向速度(向左为负)

float yVelocity = mVelocityTracker.getYVelocity();//垂直方向速度

int deltaX = 0;

int upScrollX = mItemLayout.getScrollX();

if (Math.abs(xVelocity) > 100 && Math.abs(xVelocity) > Math.abs(yVelocity)) {

if (xVelocity <= -100) {//左滑速度大于100,则删除按钮显示

deltaX = mMaxLength - upScrollX;

mDeleteBtnState = 2;

} else if (xVelocity > 100) {//右滑速度大于100,则删除按钮隐藏

deltaX = -upScrollX;

mDeleteBtnState = 1;

}

} else {

if (upScrollX >= mMaxLength / 2) {//item的左滑动距离大于删除按钮宽度的一半,则则显示删除按钮

deltaX = mMaxLength - upScrollX;

mDeleteBtnState = 2;

} else if (upScrollX < mMaxLength / 2) {//否则隐藏

deltaX = -upScrollX;

mDeleteBtnState = 1;

}

}

//item自动滑动到指定位置

mScroller.startScroll(upScrollX, 0, deltaX, 0, 200);

isStartScroll = true;

invalidate();

mVelocityTracker.clear();

break;

}

mLastX = x;

mLastY = y;

return super.onTouchEvent(e);

}

当手指抬起时,如果之前没有发生Item水平滑动、上下滑动列表、回调接口不为空,则认为是Item的点击事件,执行回调接口里的方法mListener.onItemClick(mItemLayout, mPosition);。接下来计算出手指在水平以及垂直方向的滑动速度**xVelocity 、yVelocity ,如果if (Math.abs(xVelocity) > 100 && Math.abs(xVelocity) > Math.abs(yVelocity)),则根据速度判断手指抬起后Item的滑动情况,if (xVelocity <= -100)代表左滑速度大于等于100,则将mDeleteBtnState值改为2,代表删除按钮将要打开(展示),同理如果右滑速度大于100则删除按钮将要关闭(隐藏),同时计算出相应的滑动距离deltaX **。如果不满足通过速度的判断条件则根据Item的滑动距离来判断,如果if (upScrollX >= mMaxLength / 2),即Item左滑的距离大于等于删除按钮宽度的一半,则将mDeleteBtnState值改为2,否则将mDeleteBtnState值改为1,同时不要忘了计算deltaX的值。最后通过mScroller.startScroll(upScrollX, 0, deltaX, 0, 200);使Item滑动到指定位置。

到这里我们的onTouchEvent()实现原理就分析完了。

再贴一下computeScroll()的代码:

public void computeScroll() {

if (mScroller.computeScrollOffset()) {

mItemLayout.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());

invalidate();

} else if (isStartScroll) {

isStartScroll = false;

if (mDeleteBtnState == 1) {

mDeleteBtnState = 0;

}

if (mDeleteBtnState == 2) {

mDeleteBtnState = 3;

}

}

}

其中isStartScroll代表手指抬起后Item自动滑动的状态,在MotionEvent.ACTION_DOWN我们将其赋值为true,代表开始自动滑动,如果自动滑动结束则会执行else if中的逻辑,重置isStartScroll、修改mDeleteBtnState最终的状态值(打开或者关闭)。

手指上下滑动列表时,我们通过onScrollStateChanged()方法,监听列表滑动的状态:

public void onScrollStateChanged(int state) {

super.onScrollStateChanged(state);

isDragging = state == SCROLL_STATE_DRAGGING;

}

以判断是否正在上下滑动列表。

到此,我们把大致的实现方法就分析完了,如有不合理的地方欢迎指出!!!如有兴趣可下载源码看看:点我下载哦

android 侧滑删除方法,Android 基于RecyclerView的Item侧滑删除相关推荐

  1. android 人脸识别 方法研究,基于Android平台的人脸识别技术研究

    摘要: 在计算机视觉与模式识别领域中,人脸检测与识别技术是一个非常热门的研究课题,同时也具备非常广阔的商业价值.在诸多的目标检测算法中,基于AdaBoost算法的目标检测方法具有检测速度快,检测效果好 ...

  2. android avd 使用方法,Android中Android Virtual Device(AVD)使用教程

    AVD的全称为:Android Virtual Device,就是Android运行的虚拟设备,他是Android的模拟器识别.建立的Android要运行,必须创建AVD,每个AVD上可以配置很多的运 ...

  3. android 提供的方法,Android编程之创建自己的内容提供器实现方法

    本文实例讲述了Android编程之创建自己的内容提供器实现方法.分享给大家供大家参考,具体如下: 我们学习了如何在自己的程序中访问其他应用程序的数据.总体来说思 路还是非常简单的,只需要获取到该应用程 ...

  4. Android代码混淆方法,Android 代码混淆零基础入门

    内容提要 本篇文章主要有三个部分,让读者读完后能自己写规则混淆项目 对Android代码怎么开启混淆做一个简单的介绍. 对混淆规则做一个简单介绍: 在混淆过后Crash日志反推代码工具retrace. ...

  5. android 静态工厂方法,Android 源码中的静态工厂方法

    我们知道工厂模式有三兄弟,通常我们说的工厂模式指的是工厂方法模式,它的应用频率最高.本篇博客分享的简单工厂模式是工厂方法模式的"小弟",确切的来讲它不属于设计模式,而是一种方法.此 ...

  6. android程序设计排序方法,Android编程之可以实现拖动排序的listview控件

    DragSortListView是一个可以实现拖动排序的listview控件,是我看到的交互较为复杂的开源代码中不管是代码质量还是流畅性都最好的. DragSortListView 简称DSLV,继承 ...

  7. android layoutinflater 高度,探究LayoutInflater和RecyclerView中item设置宽高无效

    1. LayoutInflater是做什么的 Instantiates a layout XML file into its corresponding {@link android.view.Vie ...

  8. android datepicker使用方法,android DatePicker

    Date Picker 提供了一个构件去选择一个时间,使用DatePicker构件,该构件允许用户去选择月,日,年在一个界面中. 实例介绍 首先我们应该先创建一个DatePickerDialog,该D ...

  9. android view使用方法,Android View构造方法第三参数使用方法详解

    我们都知道,在Android中要使用一个View,一般会有两种方式: 在XML文件中配置: 直接在代码中new一个View的对象. 我们今天讨论的内容就是围绕着View的构造方法的. 1.实例 首先我 ...

  10. android返回键方法,Android按返回键(后退键)Back键事件捕获的两种方法

    package zhangphil.back; import android.support.v7.app.ActionBarActivity; import android.util.Log; im ...

最新文章

  1. Solidity合约记录——(三)如何在合约中对操作进行权限控制
  2. 使用DotfuscatorPro_4.9对软件dll库进行加密
  3. B1208 [HNOI2004]宠物收养所 平衡树||set (滑稽)
  4. 苹果开发几个常见的错误
  5. maven正确的集成命令-U-B
  6. linux losetup命令,losetup命令_Linux losetup 命令用法详解:设定与控制循环(loop)设备...
  7. 180接线_工程人必备:180页建筑机电安装标准做法图集,限领三天手慢无
  8. ASP.NETWebPage应用深入探讨
  9. linux apache 多域名配置,apache-2.4.12基于域名访问的多虚拟主机配置
  10. c++命令行解析库cmdline使用
  11. JVM实战总结:一个多线程中对象引用的问题
  12. 如何在Eclipse中生成Native类对应的JNI的.h文件
  13. 人工智能写作:想要和智能对话 本AI给你的写作指个路
  14. MyBatis(二)------使用JDBC编程问题总结
  15. minic 词法单元建立
  16. 杨辉三角php程序,PHP写杨辉三角实例代码
  17. 神舟微型计算机系统重装步骤,神舟笔记本电脑重装系统步骤介绍【图解】
  18. WARN: Establishing SSL connection without server‘s identity verification
  19. PyCharm使用技巧:windows下快捷键Ctrl+Alt+左箭头(后退)和Ctrl+Alt+右箭头(前进)冲突问题
  20. 你那么年轻却窥觑整个世界,你那么浮躁却想要看透生活

热门文章

  1. tensorflow模型量化篇(1)量化方法及动态范围量化
  2. 神秘的百度工业互联网,到底有多厉害?
  3. 民数记研读3——于宏洁
  4. webgl天空盒边界缝隙_基于webGL技术的3D库ThingJS支持天空盒技术实现
  5. ac服务器自动掉线,AC68U经常掉线重连 什么原因?
  6. 门萨--高智商者的集中营
  7. c语言1 2.5*3,若有如下变量定义并赋值:inta=1,b=2,c=3,k;float f=2.5,e;doubled=2.4,g;则下列符合C语言语法的...
  8. html怎么创建页面书签链接,如何:在“设计”视图中为 Web 窗体页插入 HTML 超链接和书签...
  9. 读后感:八部众---走出软件作坊:三五个人十来条枪 如何成为开发正规军(二十三)
  10. cents7安装docker并部署nginx、mysql容器