十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
先给大家展示下效果图,如果感觉不错,请参考实现代码:
10年积累的成都网站设计、网站制作、外贸营销网站建设经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有淅川免费网站建设让你可以放心的选择与我们合作。序言最近项目中需要用到滑动删除,然后去网上搜了一下,发现现有网上的各种解决办法各式各样,但是还是找不到一个能将所有细节和逻辑处理好的,至于滑动删除部分,我觉得处理的相对比较好的是 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) { } });