中国军事论坛,变成女友的那一天,喜y羊与灰太狼全集
大多数博客实现的只是当手指 down 的时候,通过判断左右滑动和上下滑动的距离之比来判断 item 是否应该滑动;但是有一个问题就是,用户 down 的时候获得焦点的 item ,但是 move 的时候手指离开了该 item 的时候应该如何处理呢? 按照正常的用户逻辑,这时仍然应该是该 item 处理滑动事件最重要和最难的部分当然也是滑动冲突了,即不管使用 recyclerview 还是使用 listview 实现,其都存在处理上下滑动和左右滑动的冲突问题,很明显的是我们不能一味地拦截所有事件,因为对于上下滑动事件还需要交给 recyclerview/listview 来实现正常的上下滑动;滑动冲突部分如果处理不好的话会出现很明显的卡顿现象,同时也会出现不符合用户心理预期的响应,而这些都是用户不友好的另外,现有的资料都是在自己的代码实现上讲解的,对于实现正真的定制化还是很有难度的,当我们想要实现自己想要的功能时,我们还需要去看懂一些不相关的处理逻辑
如果当前有 item 正在侧滑,那么 recyclerview 就不能再同时上下滑动如果当前有 item 处于打开状态,那么在下一次 down 的时候应该先将其关闭,同时在 up 之前,move 事件都应该是无效的(对于这种情况,也可以按照自己的逻辑处理,如: 如果当前有 item 处于打开状态,那么在下一次 down 的时候应该先将其关闭,但是在关闭之后,在 up 之前出现的 move 事件也应该响应)在一次 down->move...move->up 的完整过程中,一旦初始判断决定了应该是上下滑动或者 item 的左右滑动之后,在 move 过程中就不能改变,直至下一次新的判断过程为止(这种情况容易出现在用户在一次过程中反复的上下滑动时突然来一次左右滑动(或者反复的左右滑动过程中,突然来一次上下滑动))
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 的平滑滑动和添加各种动画之类的,读者可以自行决定,这个不是本文的重点
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 apk 项目一键打包并上传到蒲公英的实现方法
Android 自定义LineLayout实现满屏任意拖动功能的示例代码
android 限制某个操作每天只能操作指定的次数(示例代码详解)
Android 集成 google 登录并获取性别等隐私信息的实现代码
网友评论