- 浏览: 5825921 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (890)
- WindowsPhone (0)
- android (88)
- android快速迭代 (17)
- android基础 (34)
- android进阶 (172)
- android高级 (0)
- android拾遗 (85)
- android动画&效果 (68)
- Material Design (13)
- LUA (5)
- j2me (32)
- jQuery (39)
- spring (26)
- hibernate (20)
- struts (26)
- tomcat (9)
- javascript+css+html (62)
- jsp+servlet+javabean (14)
- java (37)
- velocity+FCKeditor (13)
- linux+批处理 (9)
- mysql (19)
- MyEclipse (9)
- ajax (7)
- wap (8)
- j2ee+apache (24)
- 其他 (13)
- phonegap (35)
最新评论
-
Memories_NC:
本地lua脚本终于执行成功了,虽然不是通过redis
java中调用lua脚本语言1 -
ZHOU452840622:
大神://处理返回的接收状态 这个好像没有监听到 遇 ...
android 发送短信的两种方式 -
PXY:
拦截部分地址,怎么写的for(int i=0;i<lis ...
判断是否登录的拦截器SessionFilter -
maotou1988:
Android控件之带清空按钮(功能)的AutoComplet ...
自定义AutoCompleteTextView -
yangmaolinpl:
希望有表例子更好。。。,不过也看明白了。
浅谈onInterceptTouchEvent、onTouchEvent与onTouch
ViewPager 作为一个横向滚动的控件, 在 ViewGroup 中嵌套时会有一些可以优化的细节体验.
问题说明
当 SwipeRefreshLayout 中有 ViewPager 控件, 两者的滑动会相互冲突. 具体表现为 ViewPager 的左右滑动不顺畅, 容易被 SwipeRefreshLayout 拦截(即出现刷新的 View ).
问题原因:
ViewPager 本身是处理了滚动事件的冲突, 它在横向滑动时会调用 requestDisallowInterceptTouchEvent() 方法使父控件不拦截当前的 Touch 事件序列. 但是 SwipeRefreshLayout 的 requestDisallowInterceptTouchEvent() 方法置空了, 所以仍然会拦截当前的 Touch 事件序列.
问题分析:
为什么 SwipeRefreshLayout 的 requestDisallowInterceptTouchEvent() 方法什么都不做?
首先 SwipeRefreshLayout 继承自 ViewGroup .
在 requestDisallowInterceptTouchEvent() 方法置空的情况下, 用户可以从底部下拉刷新一次拉出 LoadingView (即手指不需要离开屏幕).
如果方法调用 ViewGroup 的 requestDisallowInterceptTouchEvent() 方法, 可以解决 ViewPager 的 兼容问题, 但是用户在界面底部下拉至头部后, 无法继续下拉, 需要手指放开一次才能拉出 LoadingView .
目标分析:
那么为了更加顺滑地滚动, 想要的效果当然是 一次性拉出 LoadingView .既然 ViewPager 在左右滑动时才会调用 requestDisallowInterceptTouchEvent() 方法, 那么 SwipeRefreshLayout 只应该在上下滑动时 才拦截 Touch 事件.
代码具体逻辑如下:
记录是否调用了 requestDisallowInterceptTouchEvent() 方法,并且设置为true.
在 SwipeRefreshLayout 中判断是否是上下滑动.
如果同时满足1,2, 则调用 super.requestDisallowInterceptTouchEvent(true) 拦截事件.
否则调用 super.requestDisallowInterceptTouchEvent(false) .
注意:因为 ViewGroup 的 requestDisallowInterceptTouchEvent 方法返回 true 后, 接下来的 Touch 事件在不会再传递到 onInterceptTouchEvent() 方法中, 所以需要在 dispatchTouchEvent() 方法中判断是否为上下滑动.
实现代码(部分):
案例二: ViewPager 与 RecyclerView
如上图, RecyclerView 中嵌套 ViewPager .
问题说明
当用户滑动 RecyclerView 后放开手指, RecyclerView 会继续滑动并处于 Fling 状态.
此时用户重新触摸屏幕, RecyclerView 滑动停止, 但是无法左右滑动 ViewPager , 只能上下滑动 RecyclerView .
问题原因
当用户重新触摸屏幕, 此时 RecyclerView 的 onInterceptTouchEvent() 方法还是返回了 true , 所以 ViewGroup 还是继续拦截了事件, 导致 ViewPager 无法处理.
解决思路
如果是 Fling 状态的 RecyclerView , 在处理 ACTION_DOWN 事件时, 应该与 IDLE 状态下保持一致.
Fling 状态下处理 ACTION_DOWN , onInterceptTouchEvent() 方法应该返回 false.
实现代码:
案例三: ViewPager 与 ScrollView
在 ScrollView 嵌套 ViewPager , Fling 状态下会有跟 RecyclerView 一样的问题, 所以解决思路也是一样的, 只是代码部分有所不同.
问题说明
当 SwipeRefreshLayout 中有 ViewPager 控件, 两者的滑动会相互冲突. 具体表现为 ViewPager 的左右滑动不顺畅, 容易被 SwipeRefreshLayout 拦截(即出现刷新的 View ).
问题原因:
ViewPager 本身是处理了滚动事件的冲突, 它在横向滑动时会调用 requestDisallowInterceptTouchEvent() 方法使父控件不拦截当前的 Touch 事件序列. 但是 SwipeRefreshLayout 的 requestDisallowInterceptTouchEvent() 方法置空了, 所以仍然会拦截当前的 Touch 事件序列.
问题分析:
为什么 SwipeRefreshLayout 的 requestDisallowInterceptTouchEvent() 方法什么都不做?
首先 SwipeRefreshLayout 继承自 ViewGroup .
在 requestDisallowInterceptTouchEvent() 方法置空的情况下, 用户可以从底部下拉刷新一次拉出 LoadingView (即手指不需要离开屏幕).
如果方法调用 ViewGroup 的 requestDisallowInterceptTouchEvent() 方法, 可以解决 ViewPager 的 兼容问题, 但是用户在界面底部下拉至头部后, 无法继续下拉, 需要手指放开一次才能拉出 LoadingView .
目标分析:
那么为了更加顺滑地滚动, 想要的效果当然是 一次性拉出 LoadingView .既然 ViewPager 在左右滑动时才会调用 requestDisallowInterceptTouchEvent() 方法, 那么 SwipeRefreshLayout 只应该在上下滑动时 才拦截 Touch 事件.
代码具体逻辑如下:
记录是否调用了 requestDisallowInterceptTouchEvent() 方法,并且设置为true.
在 SwipeRefreshLayout 中判断是否是上下滑动.
如果同时满足1,2, 则调用 super.requestDisallowInterceptTouchEvent(true) 拦截事件.
否则调用 super.requestDisallowInterceptTouchEvent(false) .
注意:因为 ViewGroup 的 requestDisallowInterceptTouchEvent 方法返回 true 后, 接下来的 Touch 事件在不会再传递到 onInterceptTouchEvent() 方法中, 所以需要在 dispatchTouchEvent() 方法中判断是否为上下滑动.
实现代码(部分):
//非法按键 private static final int INVALID_POINTER = -1; //dispatch方法记录第一次按下的x private float mInitialDisPatchDownX; //dispatch方法记录第一次按下的y private float mInitialDisPatchDownY; //dispatch方法记录的手指 private int mActiveDispatchPointerId = INVALID_POINTER; //是否请求拦截 private boolean hasRequestDisallowIntercept = false; @Override public void requestDisallowInterceptTouchEvent(boolean b) { hasRequestDisallowIntercept = b; // Nope. } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mActiveDispatchPointerId = MotionEventCompat.getPointerId(ev, 0); final float initialDownX = getMotionEventX(ev, mActiveDispatchPointerId); if (initialDownX != INVALID_POINTER) { mInitialDisPatchDownX = initialDownX; } final float initialDownY = getMotionEventY(ev, mActiveDispatchPointerId); if (mInitialDisPatchDownY != INVALID_POINTER) { mInitialDisPatchDownY = initialDownY; } break; case MotionEvent.ACTION_MOVE: if (hasRequestDisallowIntercept) { //解决viewPager滑动冲突问题 final float x = getMotionEventX(ev, mActiveDispatchPointerId); final float y = getMotionEventY(ev, mActiveDispatchPointerId); if (mInitialDisPatchDownX != INVALID_POINTER && x != INVALID_POINTER && mInitialDisPatchDownY != INVALID_POINTER && y != INVALID_POINTER) { final float xDiff = Math.abs(x - mInitialDisPatchDownX); final float yDiff = Math.abs(y - mInitialDisPatchDownY); if (xDiff > mTouchSlop && xDiff * 0.7f > yDiff) { //横向滚动不需要拦截 super.requestDisallowInterceptTouchEvent(true); } else { super.requestDisallowInterceptTouchEvent(false); } } else { super.requestDisallowInterceptTouchEvent(false); } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { hasRequestDisallowIntercept = false; } break; } return super.dispatchTouchEvent(ev); } private float getMotionEventY(MotionEvent ev, int activePointerId) { final int index = MotionEventCompat.findPointerIndex(ev, activePointerId); if (index < 0) { return -1; } return MotionEventCompat.getY(ev, index); } private float getMotionEventX(MotionEvent ev, int activePointerId) { final int index = MotionEventCompat.findPointerIndex(ev, activePointerId); if (index < 0) { return -1; } return MotionEventCompat.getX(ev, index); }
案例二: ViewPager 与 RecyclerView
如上图, RecyclerView 中嵌套 ViewPager .
问题说明
当用户滑动 RecyclerView 后放开手指, RecyclerView 会继续滑动并处于 Fling 状态.
此时用户重新触摸屏幕, RecyclerView 滑动停止, 但是无法左右滑动 ViewPager , 只能上下滑动 RecyclerView .
问题原因
当用户重新触摸屏幕, 此时 RecyclerView 的 onInterceptTouchEvent() 方法还是返回了 true , 所以 ViewGroup 还是继续拦截了事件, 导致 ViewPager 无法处理.
解决思路
如果是 Fling 状态的 RecyclerView , 在处理 ACTION_DOWN 事件时, 应该与 IDLE 状态下保持一致.
Fling 状态下处理 ACTION_DOWN , onInterceptTouchEvent() 方法应该返回 false.
实现代码:
@Override public boolean onInterceptTouchEvent(MotionEvent e) { //isScrolling 为 true 表示是 Fling 状态 boolean isScrolling = getScrollState() == SCROLL_STATE_SETTLING; boolean ans = super.onInterceptTouchEvent(e); if (ans && isScrolling && e.getAction() == MotionEvent.ACTION_DOWN) { //先调用 onTouchEvent() 使 RecyclerView 停下来 onTouchEvent(e); //反射恢复 ScrollState try { Field field = RecyclerView.class.getDeclaredField("mScrollState"); field.setAccessible(true); field.setInt(this, SCROLL_STATE_IDLE); } catch (NoSuchFieldException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { e1.printStackTrace(); } return false; } return ans; }
案例三: ViewPager 与 ScrollView
在 ScrollView 嵌套 ViewPager , Fling 状态下会有跟 RecyclerView 一样的问题, 所以解决思路也是一样的, 只是代码部分有所不同.
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean ans = super.onInterceptTouchEvent(ev); if (ans && ev.getAction() == MotionEvent.ACTION_DOWN) { onTouchEvent(ev); Field field = null; try { field = NestedScrollView.class.getDeclaredField("mIsBeingDragged"); } catch (NoSuchFieldException e) { e.printStackTrace(); } if (field != null) { field.setAccessible(true); try { field.setBoolean(this, false); } catch (IllegalAccessException e) { e.printStackTrace(); } } return false; } return ans; }
发表评论
-
某些android手机获取不到IMEI问题
2018-08-21 14:17 7637某些山寨机可能拿不到IMEI 如果非要IMEI可以模拟一个 ... -
APK安装成功后点击"打开"再按Home键应用会重启的问题
2018-08-21 14:13 2774安装系统SD卡里面的apk或者原有的程序更新版本的时候, ... -
使用volley链接Https地址时报SSLHandshakeException
2018-08-21 14:06 2141在真实设备上出现以下错误 ︰ Volley error: ... -
PhotoView+Viewpager双指缩放的时候出现pointerIndex out of range问题
2017-07-10 14:30 4247PhotoView+Viewpager开发图集效果的时候,在某 ... -
Android6.0权限封装
2017-04-01 12:04 1574简介 Android6.0中对权限分为了一般权限和危险权限。 ... -
实现点击 WebView 中的图片,调用原生控件展示图片
2017-04-01 11:14 2813现在有很多时候,我们的 App 都进行了混合开发,而最简单,最 ... -
Android 方法引用数超过 65535 优雅解决
2017-03-31 09:37 1550随着应用不断迭代更新,业务线的扩展,应用越来越大(比如:集成了 ... -
android引用资源@与属性?备忘单
2017-03-30 10:09 1291几天前我偶然发现了我A ... -
Android中一些你可能没注意的小效果实现
2017-02-15 21:09 0http://www.see-source.com/blog/ ... -
Android热修复:Andfix和Hotfix,两种方案的比较与实现
2017-02-15 21:00 0http://www.see-source.com/blog/ ... -
Android 从网页中跳转到本地App
2017-01-11 09:27 1883我们在使用微信、QQ、京东等app的时候,会发现有时候通过他们 ... -
Activity的启动模式和onNewIntent
2016-12-28 09:10 1338一、启动模式介绍 启 ... -
android5.0使用Notification报RemoteServiceException的解决办法
2016-08-31 16:13 11553有时android5.0下使用Notification会报如下 ... -
RecyclerView 中的 item 如何居中问题
2016-05-18 09:52 12557一个很简单的Item布局,我只要让它由上而下排列,文字居中 ... -
sqlite3:not found 解决方法
2015-12-08 16:03 2558最最最重要,先root你的手机吧 sqlite3 为一个可 ... -
隐藏底部虚拟键NavigationBar实现全屏
2015-10-08 17:20 9857import android.app.Activity; ... -
服务端执行慢或网络延迟时,Volley多次发送请求的问题
2015-07-27 15:40 7004原文: Android Volley double post ... -
如何获取 Android 设备的CPU核数、时钟频率以及内存大小
2015-06-30 17:04 4388原帖: http://www.jianshu.com/p/f7 ... -
android点滴5
2015-04-10 17:32 2053一些小效果的实现 http://www.see-source. ... -
SwipeRefreshLayout和ListView的EmptyView共存冲突的问题
2015-01-20 11:47 18652SwipeRefreshLayout是android官方的下拉 ...
相关推荐
SwipeRefreshLayout嵌套ScrollView包裹复杂头布局和RecyclerView - Dear月的博客 - 博客频道 - CSDN.NET http://blog.csdn.net/github_36287370/article/details/52880164 的附件
4. **使用SwipeRefreshLayout**:当需要在列表顶部添加下拉刷新功能时,SwipeRefreshLayout可以智能地处理与ListView或RecyclerView的滑动冲突。 5. **使用CoordinatorLayout**:这是一种布局管理器,可以处理复杂...
然而,当多个可滑动组件(如ScrollView、HorizontalScrollView或ViewPager)共存于同一布局时,可能会出现滑动冲突的问题,即用户在尝试滑动一个组件时,另一个组件却响应了滑动事件,导致用户体验下降。本篇将深入...
- **触摸事件处理**:正确处理触摸事件,防止滑动冲突,例如在ViewPager和SwipeRefreshLayout同时存在时,需要合理分配滑动手势。 - **适配不同设备**:考虑到屏幕尺寸和方向的变化,滑动布局应具备良好的响应式设计...
9. **滑动冲突解决** - 在嵌套滚动场景中,可能会出现滑动冲突。通过覆写`requestDisallowInterceptTouchEvent()`,可以控制是否允许父视图拦截子视图的滑动事件。 10. **滑动库与第三方组件** - Android社区提供...
这个示例项目不仅展示了`ViewPager`、`ListView`、`SwipeRefreshLayout`的用法,还提供了解决常见问题的方法,对于进行毕业设计或日常的代码学习都非常有价值。 总的来说,这个项目是一个很好的学习资源,它涵盖了...
在实际开发中,可能会遇到多个滑动组件共存的情况,如ViewPager嵌套ScrollView,这时需要处理滑动冲突,确保用户的滑动意图能够被正确响应。 8. **自定义动画**: Android提供了丰富的动画API,如ObjectAnimator...
6. **滑动冲突解决**: 在复杂布局中,可能会出现多个可滑动视图导致的事件冲突。这时可以通过设置touch listener的onRequestDisallowInterceptTouchEvent()方法,禁止父视图拦截触摸事件,或者自定义滑动逻辑,避免...
当ScrollView和其他可滑动的组件(如ViewPager或NestedScrollView)放在一起时,可能会出现滑动冲突。Android提供嵌套滚动机制来解决这个问题,但有时需要自定义事件分发以正确处理触摸事件。 9. **使用...
在实际开发中,我们可能需要考虑更多因素,如滑动速度的控制、页面之间的过渡动画、滑动冲突的处理等。这些都需要我们在实践中不断调整和优化,以提供更好的用户体验。 总之,“android 左右滑屏”是Android开发中...
它允许开发者定义自己的滑动行为,同时避免了滑动冲突和不一致的问题。通过这个库,你可以轻松地为你的应用添加上拉刷新、左右滑动切换页面、下拉隐藏/显示顶部栏等多种滑动操作。 在具体实现上,`...
在Android中,滚动通常是通过滚动视图(如 ScrollView 或 HorizontalScrollView)或 RecyclerView 自动处理的。但如果你想自定义滚动行为,你可以使用滚动监听器(OnScrollListener)来捕获滚动事件,如滚动开始、...
4. **ViewPager**: ViewPager允许用户左右滑动查看多个页面,常用于实现TabLayout或者轮播图效果。通过PagerAdapter,开发者可以轻松管理多个页面的内容。 5. **DialogFragment**: 对话框在Android应用中经常使用,...
- 如果自定义View内部还包含其他可滚动组件,如SwipeRefreshLayout或ViewPager,需要处理它们之间的滚动冲突。可以使用`NestedScrollingChildHelper`和`NestedScrollingParentHelper`来协调这些组件的滚动行为。 7...