在开发场景中,经常需要Viewpager+Fragment嵌套滑动页面。然而若某个Fragment为webview,且webview中存在轮播图或者其他滑动控件,则会出现Webview内容无法左右滑动的问题。
其实滑动冲突问题的本质,是滑动事件的分发和消费不对。
一般,我们需要明确,这个事件应该由谁来消费,实际上是谁消费了,分发过程是否正确,是否需要拦截等,想清楚这些问题基本就找到解决思路了。
若对Android事件机制不够熟悉,可以先温习一遍事件机制原理再往下看。
在上述的问题场景中,我们可以确定正确思路:这个事件应该由webivew先响应,如果webview不需要内部滑动了(左右滑到边了),再交给Viewpage处理事件。
1.WebView onTouchEvent方法
查找父组件是否为可以滑动的视图(如ViewPager),是则调用requestDisallowInterceptTouchEvent(true),请求父组件不要拦截
2.WebView onOverScrolled
当clampedX或者clampedY值为true,此时不再响应内部滑动。调用requestDisallowInterceptTouchEvent(false),请求父组件恢复拦截
- //最大递归深度,避免异常,防止嵌套层级导致判断无效
- int MAX_PARENT_DEPTH = 3;
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- ViewParent viewParent = findViewParentIfNeeds(this, MAX_PARENT_DEPTH);
- if(viewParent != null){
- // 父组件不要拦截
- viewParent.requestDisallowInterceptTouchEvent(true);
- }
- }
- return super.onTouchEvent(event);
- }
-
- private ViewParent findViewParentIfNeeds(View tag, int depth){
-
- if (depth < 0) {
- return null;
- }
-
- ViewParent parent = tag.getParent();
- if (parent == null) {
- return null;
- }
-
- if (parent instanceof ScrollView || parent instanceof ViewPager){
- return parent;
- }
- return findViewParentIfNeeds((View) parent, depth - 1);
- }
- @Override
- protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY){
- if (clampedX || clampedY) {
- ViewParent viewParent = findViewParentIfNeeds(this, MAX_PARENT_DEPTH);
- if (viewParent != null) {
- // 父组件可以根据自身判断来决定是否拦截
- viewParent.requestDisallowInterceptTouchEvent(false);
- }
- }
-
- super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
- }