Android自定义滑动删除效果的实现代码

先给大家展示下效果图,如果感觉不错,请参考实现代码:

序言

最近项目中需要用到滑动删除,然后去网上搜了一下,发现现有网上的各种解决办法各式各样,但是还是找不到一个能将所有细节和逻辑处理好的,至于滑动删除部分,我觉得处理的相对比较好的是 QQ(包括处理各种逻辑和细节);最终,苦寻无果,于是决定自己动手,丰衣足食

这篇文章将从现有 Android 滑动删除的痛点,到搭建好一个基本的框架,到最终提供一份完整的 Demo为止,争取为读者提供最大的可定制化

正文

一. 滑动删除的痛点

(1). 现有资料中的不足

笔者参阅了网上的一些博客,发现,这些博客中大多能够基本实现滑动删除,但是存在的问题是,对于面向用户实际使用而言,却是远远不够的大多数博客实现的只是当手指 DOWN 的时候,通过判断左右滑动和上下滑动的距离之比来判断 Item 是否应该滑动;但是有一个问题就是,用户 DOWN 的时候获得焦点的 Item ,但是 MOVE 的时候手指离开了该 Item 的时候应该如何处理呢? 按照正常的用户逻辑,这时仍然应该是该 Item 处理滑动事件最重要和最难的部分当然也是滑动冲突了,即不管使用 RecyclerView 还是使用 ListView 实现,其都存在处理上下滑动和左右滑动的冲突问题,很明显的是我们不能一味地拦截所有事件,因为对于上下滑动事件还需要交给 RecyclerView/ListView 来实现正常的上下滑动;滑动冲突部分如果处理不好的话会出现很明显的卡顿现象,同时也会出现不符合用户心理预期的响应,而这些都是用户不友好的

另外,现有的资料都是在自己的代码实现上讲解的,对于实现正真的定制化还是很有难度的,当我们想要实现自己想要的功能时,我们还需要去看懂一些不相关的处理逻辑

(2). 需要处理的细节

我一直觉得 QQ 在处理滑动删除上做的是相对比较好的,特别是从各种细节处理上,它基本上都能给出符合用户心理预期的响应,这里也是以 QQ 为例来介绍几种需要注意和处理的细节;当然,需要注意的地方很多,一一例举不太现实,具体的还是需要自己动手啦

侧滑过程中,DOWN 时得到焦点的 Item 在 MOVE 过程中失去了焦点应该怎么处理?(即对应上面的 现有资料中的不足 中的第2项);如下图所示,手指 DOWN 的时候得到焦点的是 Item 7, 但是之后手指在 MOVE 过程中,Item 7 失去了焦点;正如上面所说,此时还是应该交由该 Item 7 处理滑动事件(如果在 DOWN 的时候已经判为侧滑的话)

如果当前有 Item 正在侧滑,那么 RecyclerView 就不能再同时上下滑动
如果当前有 Item 处于打开状态,那么在下一次 DOWN 的时候应该先将其关闭,同时在 UP 之前,MOVE 事件都应该是无效的(对于这种情况,也可以按照自己的逻辑处理,如: 如果当前有 Item 处于打开状态,那么在下一次 DOWN 的时候应该先将其关闭,但是在关闭之后,在 UP 之前出现的 MOVE 事件也应该响应)
在一次 DOWN->MOVE...MOVE->UP 的完整过程中,一旦初始判断决定了应该是上下滑动或者 Item 的左右滑动之后,在 MOVE 过程中就不能改变,直至下一次新的判断过程为止(这种情况容易出现在用户在一次过程中反复的上下滑动时突然来一次左右滑动(或者反复的左右滑动过程中,突然来一次上下滑动))

二. 一个框架

(1). 使用 RecyclerView 搭建框架

1. 预备知识

RecyclerView 对外提供的接口已经比较完善,所以不需要再去继承 RecyclerView 来监听其 MotionEvent 事件
可以通过 RecyclerView 的 addOnItemTouchListener() 方法来实现对所有 MotionEvent 的拦截,其需要传入一个 RecyclerView.OnItemTouchListener 对象,这是一个 interface ,需要我们自己来实现逻辑,这里笔者写了一个大致的 Demo 先来看看其各个方法之间的联系

recyclerView.addOnItemTouchListener(new  RecyclerView.OnItemTouchListener() {
     @Override
     public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
       switch (e.getAction()) {
         case MotionEvent.ACTION_DOWN: {
           Log.d("@HusterYP", String.valueOf("onInterceptTouchEvent DOWN"));
           break;
         }
         case MotionEvent.ACTION_MOVE: {
           Log.d("@HusterYP", String.valueOf("onInterceptTouchEvent MOVE"));
           break;
         }
         case MotionEvent.ACTION_UP: {
           Log.d("@HusterYP", String.valueOf("onInterceptTouchEvent UP"));
           break;
         }
       }
       return true;
     }
     @Override
     public void onTouchEvent(RecyclerView rv, MotionEvent e) {
       switch (e.getAction()) {
         case MotionEvent.ACTION_MOVE: {
           Log.d("@HusterYP", String.valueOf("onTouchEvent MOVE"));
           break;
         }
         case MotionEvent.ACTION_UP: {
           Log.d("@HusterYP", String.valueOf("onTouchEvent UP"));
           break;
         }
       }
     }
     @Override
     public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
     }
   });

关于该 Demo 的代码可至笔者 Github 上下载执行测试;这里笔者就直接给出在 onInterceptTouchEvent 方法中返回不同值时的结论了:

如果在最后返回 false,那么 DOWN,MOVE,UP事件都是交给 onInterceptTouchEvent 处理可上下滚动
如果在最后返回 true,那么 onInterceptTouchEvent 只会接受到一个 DOWN,一个 MOVE;但是onTouchEvent 接收到剩下的 MOVE 和 UP; 不可上下滚动

如果最后返回 false,但是在 onInterceptTouchEvent 的 DOWN 判断中返回 true,这种情况同1
如果最后返回 false 或者 true,但是在 onInterceptTouchEvent 的 DOWN 判断中调用rv.setLayoutFrozen(true);方法,那么 onInterceptTouchEvent 只会收到一个 DOWN

如果在最后返回 false,但是在 onInterceptTouchEvent 的 MOVE 判断中 return true;的话,同情况2
那么通过上面的预备知识和结论,我们实现的滑动删除的思路也就渐渐清晰了:

最关键的是如何判断应该是 Item 的横向滑动还是 RecyclerView 的上下滑动,这里可以通过判断手指滑动的速度来判断: 即在 onInterceptTouchEvent 方法中的 MOVE 事件中去判断,如果 x 向速度大于 y 向速度,那么可以判断为是 Item 的横向滑动,直接 return true 即可,正如上面分析的那样,之后直接在 onTouchEvent 方法中处理 Item 的滑动逻辑即可;这里还有一点需要注意的是,在 onInterceptTouchEvent 的 MOVE 事件中判断时,对于一个完整的 DOWN->MOVE...MOVE->UP 过程,其实只需要,也只能执行一次判断,因为对于这样一个完整的过程,一旦在初始 MOVE 中将该过程判断为 Item 左右滑动或者 RecyclerView 上下滑动之后,中间就不可能突然改变,这对应上面 需要处理的细节 中的情况5;所以这里笔者是通过一个标志变量(flag)来实现的,需要注意的是在 UP 之后需要把 flag 置位,方便下一次判断

对于当手指 DOWN 时,已经有了一个 Item 处于打开状态,那么此时也应该分情况,当此时手指 DOWN 处仍然为该打开 Item 时,那么手指的移动情况就应该交给该 Item 来处理;如果此时手指 DOWN 的位置不是该打开 Item ,那么合理的处理是先关闭该 Item,之后在该过程中的 MOVE 事件还要不要响应,其实笔者觉得都是可以接受的;至于具体的细节处理是设置两个 ViewHolder 变量来记录(curHolder和oldHolder)即可,可在 onInterceptTouchEvent 中的 DOWN 事件中判断

至于 Item 的平滑滑动和添加各种动画之类的,读者可以自行决定,这个不是本文的重点

三. 一个可扩展的Demo

这里给出笔者实现的一个完整 Demo,代码中也有部分注释,可以结合本文再来理清一下逻辑
完整Demo代码可以到笔者 Github 下载

同时,读者也可以根据自己的实际需要,重新设置布局和重新添加一些自己的滑动逻辑;需要需要解释的是,这里笔者为了实现平滑移动,所以继承了 RelativeLayout 在实现了一个 MyRelativeLayout 类,即最外层布局,如下可知,笔者只是简单的在其中使用了一个 Scroller 类来实现平滑移动,其他也没有复杂的操作

public class MyRelativeLayout extends RelativeLayout {
private Scroller scroller;
 public MyRelativeLayout(Context context) {
   super(context);
   init(context);
 }
 public MyRelativeLayout(Context context, AttributeSet attrs) {
   super(context, attrs);
   init(context);
 }
 public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
   super(context, attrs, defStyleAttr);
   init(context);
 }
 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
 public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
   super(context, attrs, defStyleAttr, defStyleRes);
   init(context);
 }
 private void init(Context context) {
   scroller = new Scroller(context);
 }
 public void onScroll(int dx) {
   if (this.getScrollX() != 0) {
     scroller.startScroll(this.getScrollX(), 0, dx, 0);
     invalidate();
   }
 }
 @Override
 public void computeScroll() {
   super.computeScroll();
   if (scroller.computeScrollOffset()) {
     this.scrollTo(scroller.getCurrX(), 0);
     invalidate();
   }
 }
}

总结

以上所述是小编给大家介绍的Android自定义滑动删除效果的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android仿微信列表滑动删除之可滑动控件(一)

    这次是列表滑动删除的第三波,仿微信的列表滑动删除.先上个效果图: 前面的文章里面说过开源框架SwipeListView的实现原理是每个列表item中包含上下两层view,普通状态下上层的view覆盖着下层的view,当用户滑开上层的view,下层的view就显示出来了.但是仔细观察微信列表的item,很明显并非这个实现方案,微信的item应该一个单层view,只不过这个item超出了所在的ListView的宽度,在用户滑动item的时候,item超出屏幕的view则会显示在屏幕之上,这种滑动实现

  • Android 滑动监听RecyclerView线性流+左右划删除+上下移动

    废话不多说了,直接给大家贴代码了.具体代码如下所示: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_wid

  • Android仿微信滑动弹出编辑、删除菜单效果、增加下拉刷新功能

    如何为不同的list item呈现不同的菜单,本文实例就为大家介绍了Android仿微信或QQ滑动弹出编辑.删除菜单效果.增加下拉刷新等功能的实现,分享给大家供大家参考,具体内容如下 效果图: 1. 下载开源项目,并将其中的liberary导入到自己的项目中: 2. 使用SwipeMenuListView代替ListView,在页面中布局: <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefresh

  • 详解Android中实现ListView左右滑动删除条目的方法

    使用Scroller实现绚丽的ListView左右滑动删除Item效果 这里来给大家带来使用Scroller的小例子,同时也能用来帮助初步解除的读者更加熟悉的掌握Scroller的使用,掌握好了Scroller的使用我们就能实现很多滑动的效果.例如侧滑菜单,launcher,ListView的下拉刷新等等效果,我今天实现的是ListView的item的左右滑动删除item的效果,现在很多朋友看到这个效果应该是在Android的通知栏下拉中看到这个滑动删除的效果吧,我看到这个效果是在我之前的三星手

  • Android开发中模仿qq列表信息滑动删除功能

    这个效果的完成主要分为两个部分 自定义view作为listview的列表项 一个view里面包括 显示头像,名字,消息内容等的contentView和滑动才能显示出来的删除,置顶的右边菜单menuView 在手指移动的时候同时改变这两个视图的位置 重写listview 判断item向左还是向右滑动 正常的滚动还是左右滑动等等 重写onTouchEvent 进行事件分发 大致思路: listview进行事件分发,判断需要滑动还是滚动等状态,如果需要滑动将事件传递给item进行滑动处理. 在item

  • Android下拉刷新上拉加载更多左滑动删除

    一.前言 老规矩,别的不说,这demo是找了很相关知识集合而成的,可以说对我这种小白来说是绞尽脑汁!程序员讲的是无图无真相! 现在大家一睹为快! 二.比较关键的还是scroller这个类的 package com.icq.slideview.view; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue;

  • Android自定义滑动删除效果的实现代码

    先给大家展示下效果图,如果感觉不错,请参考实现代码: 序言 最近项目中需要用到滑动删除,然后去网上搜了一下,发现现有网上的各种解决办法各式各样,但是还是找不到一个能将所有细节和逻辑处理好的,至于滑动删除部分,我觉得处理的相对比较好的是 QQ(包括处理各种逻辑和细节);最终,苦寻无果,于是决定自己动手,丰衣足食 这篇文章将从现有 Android 滑动删除的痛点,到搭建好一个基本的框架,到最终提供一份完整的 Demo为止,争取为读者提供最大的可定制化 正文 一. 滑动删除的痛点 (1). 现有资料中

  • Android自定义滑动验证条的示例代码

    本文介绍了Android自定义滑动验证条的示例代码,分享给大家,具体如下: *注:不知道为什么,h5的标签在这里没用了,所以我也只能用Markdown的语法来写了 项目地址:https://github.com/994866755/handsomeYe.seekbar.github.io 需求: 在我们的某些应用中需要滑动验证.比如说这个样子的: 刚开始我也很懵逼要怎么去弄,结果我去看了一些人的代码,有人是用自定义viewgroup去做,就是viewgroup包含滑动块和滑动条.但我觉得太麻烦,

  • react-native 实现购物车滑动删除效果的示例代码

    购物车的功能基本上电商项目都会有的,这是一篇关于react-native的,原生android的已经好久没写了.记得以前写原生购物车的时候,遇到过产品的灵魂质问,为啥iOS的滑动删除可以,android却那么难实现的.这个时候,我就打开微信说,android的微信版也是长按进行操作,iOS的是滑动操作的,两个平台自带的系统交互操作是不一样的.当然,最后还是默默的找各种三方库去进行滑动删除. rn的项目也是找的网上的一个三方库进行列表滑动操作的,github地址react-native-swipe

  • android 自定义圆角button效果的实例代码(自定义view Demo)

    概述 在平时开发过程中经常会碰到需要使用圆角button的情况,一般也会包括很多其他小功能,比如要在里面添加img,设置不同的圆角大小等. 针对这样的场景,直接使用创建多个shape,定义多个xml文件也是可以实现的.但是如果使用非常频繁,那么直接自定义一个就会来的非常方便. 甚至在一些情况下,不是可以用shape定义的规则图形,比如需要用到贝塞尔曲线等. 如果全局需要这样风格的view,那么自定义一个View是非常必要的. 本文主要是个demo记录,如有需要的读者可以借鉴学习. Demo 主要

  • Android自定义控制条效果

    本文实例为大家分享了Android自定义控制条效果的具体代码,供大家参考,具体内容如下 ControlBar 自定义一个可以调节大小的控件,可以根据宽高来指定控制条方向.当width >= heigth时,为横向控制条,否则为竖向控制条 onMeasure 根据用户给定的width与height计算控制条的坐标. 1.主要的计算思路 先计算横向的的坐标点,竖向的坐标点即横向的逆时针旋转90度再向下移一个heigth的长度. //横向坐标点 mHorLArcFirstPathX = mRadius

  • Android自定义悬浮按钮效果

    本文实例为大家分享了Android自定义悬浮按钮效果的具体代码,供大家参考,具体内容如下 以下:内容没有参考,写的也是一个比较简单的例子,主要就是应用切换前后台时会显示/隐藏悬浮窗.内容仅用于自我记录学习使用. 项目的开发时应用在登陆后显示一个悬浮窗,同时显示在线人数等一些其他信息,点击悬浮按钮可以显示全局弹窗名单.开发完成后,觉着需要记录一下这种实现方式.所以写一个简单的Demo. Demo思路是通过启动Service来添加/移除 悬浮窗,因为是一个全局悬浮窗,所以选择依附于Service.

  • Android自定义选项卡切换效果

    本文实例为大家分享了Android自定义选项卡切换效果的具体代码,供大家参考,具体内容如下 一.实际使用的效果 二.自定义可切换的标题栏 1.布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas

  • Android高仿微信对话列表滑动删除效果

    前言 用过微信的都知道,微信对话列表滑动删除效果是很不错的,这个效果我们也可以有.思路其实很简单,弄个ListView,然后里面的每个item做成一个可以滑动的自定义控件即可.由于ListView是上下滑动而item是左右滑动,因此会有滑动冲突,也许你需要了解下android中点击事件的派发流程,请参考Android源码分析-点击事件派发机制.我的解决思路是这样的:重写ListView的onInterceptTouchEvent方法,在move的时候做判断,如果是左右滑动就返回false,否则返

  • Android使用SwipeListView实现类似QQ的滑动删除效果

    QQ的滑动删除效果很不错,要实现这种效果,可以使用SwipeListView. 1. 下载com.fortysevendeg.swipelistview这个项目(以前GitHub上有,现在GitHub上没有了,百度了很多次才下载到的),导入Eclipse,右键单击,选择Properties->Android,选中Library下面的IsLibrary. 2. 新建一个项目MySwipeListView,加入SwipeListView这个库. 3. 在主窗体里面放入一个SwipeListView控

  • Android仿微信对话列表滑动删除效果

    微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重构,最终实现了微信对话列表滑动删除效果. 实现原理  1.通过ListView的pointToPosition(int x, int y)来获取按下的position,然后通过android.view.ViewGroup.getChildAt(position)来得到滑动对象swipeView  2

随机推荐