美文网首页Android开发过程中遇到的坑
Android中WebView和父控件滑动冲突

Android中WebView和父控件滑动冲突

作者: enjoy_coding | 来源:发表于2019-04-16 13:06 被阅读0次

    问题场景 在项目的App中有一个ViewPager,它内部包含了WebView,而内部的webview加载了一个可以左右滑动的网页。当我们在网页滑动的时候,会直接切换到下一个WebView的页面,而不是优先响应WebView的滑动,这样一来WebView和ViewPager的滑动就出现了冲突。

    但是产品期望场景是当手指落到WebView的可滑动区域是相应WebView的滑动事件,当滑动到边缘之后再相应ViewPager的滑动事件。

    解决思路如下:

    1. 首先响应WebView的滑动事件
    2. WebView的滑动事件完成,响应父控件的滑动事件

    有了以上思路我们就能着手实现了,但是我们怎么能检测到WebView的滑动事件完成了呢?原来WebView的实现者也考虑到了这方面的需求,它暴露了一个方法

    @Override
        protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
            mProvider.getViewDelegate().onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        }
    

    官方文档描述如下图:


    WebView的onOverScrolled方法.png

    通过上述方法我能就能监测到WebView滑动到了边界,接下来就是对拦截事件的处理了:

    1. 在WebView的onTouchEvent事件为ACTION_DOWN时,查找父视图是否是可以滑动的视图(如ViewPager),如果是,则通过调用requestDisallowInterceptTouchEvent(true),请求父视图不要拦截touchEvent事件

    2. 如果WebView不再响应内部滑动(即onOverScrolled中clampedX或者clampedY值为true),我们再起调用requestDisallowInterceptTouchEvent(false)请求父视图恢复拦截处理touchEvent事件.
      好了思路和方法都有了那我就就开始通过重写WebView的方法来实现我们的功能了,具体代码如下:

    class CommonWebView : WebView {
    
        constructor(context: Context) : super(context)
    
        constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    
        constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    
    
        override fun onTouchEvent(event: MotionEvent): Boolean {
            if (event.actionMasked == MotionEvent.ACTION_DOWN) {
                val viewParent = findViewParentIfNeeds(this)
                viewParent?.requestDisallowInterceptTouchEvent(true)
            }
            return super.onTouchEvent(event)
        }
    
        override fun onOverScrolled(scrollX: Int, scrollY: Int, clampedX: Boolean, clampedY: Boolean) {
            if (clampedX) {//水平判断
                val viewParent = findViewParentIfNeeds(this)
                viewParent?.requestDisallowInterceptTouchEvent(false)
            }
            super.onOverScrolled(scrollX, scrollY, clampedX, clampedY)
        }
    
        private fun findViewParentIfNeeds(tag: View): ViewParent? {
            val parent = tag.parent
            if (parent == null) {
                return parent
            }
            return if (parent is ViewPager ||
                parent is AbsListView ||
                parent is ScrollView ||
                parent is HorizontalScrollView ||
                parent is GridView
            ) {
                parent
            } else {
                if (parent is View) {
                    findViewParentIfNeeds(parent as View)
                } else {
                    parent
                }
            }
        }
    }
    

    通过上述处理就能完美解决开篇的问题。

    相关文章

      网友评论

        本文标题:Android中WebView和父控件滑动冲突

        本文链接:https://www.haomeiwen.com/subject/xutbwqtx.html