Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebView嵌套滑动冲突终极解决方案 #1287

Open
michaellee123 opened this issue Dec 18, 2020 · 10 comments
Open

WebView嵌套滑动冲突终极解决方案 #1287

michaellee123 opened this issue Dec 18, 2020 · 10 comments

Comments

@michaellee123
Copy link

在WebView下拉刷新的时候,如果html中还有自己的下拉,那在SmartRefreshLayout中就会出现各种问题。我解决了这个问题,给大家分享一下解决方案。
首先自定义WebView,代码如下:

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.webkit.WebView;

public class MyWebView extends WebView {

    public interface RefreshStateListener {
        public void refreshState(boolean canRefresh);
    }

    private RefreshStateListener refreshStateListener;

    public void setRefreshStateListener(RefreshStateListener refreshStateListener) {
        this.refreshStateListener = refreshStateListener;
    }

    public MyWebView(Context context) {
        super(context);
    }

    public MyWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        if (refreshStateListener != null) {
            refreshStateListener.refreshState(clampedY);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (refreshStateListener != null && event.getAction() == MotionEvent.ACTION_DOWN) {
            refreshStateListener.refreshState(false);
        }
        return super.onTouchEvent(event);
    }

}

使用非常简单,只需要在你的WebView那里加上一句代码即可。

webView.setRefreshStateListener {
    refreshLayout.setEnableRefresh(it)
}

目前没有发现任何问题,可以尝试使用百度首页测试。

@huaxiaolin
Copy link

腾讯webview这样也不行,有没有解决腾讯webview这种问题的

@michaellee123
Copy link
Author

腾讯webview这样也不行,有没有解决腾讯webview这种问题的

你是说X5内核那个东西吗?

@huaxiaolin
Copy link

腾讯webview这样也不行,有没有解决腾讯webview这种问题的

你是说X5内核那个东西吗?

是的,X5的这个不知道怎么实现,使用上述方法并不行,但是我看微信和QQ上应该是实现了,说明应该是有方法的,所以看你知道这个方法不?

@michaellee123
Copy link
Author

腾讯webview这样也不行,有没有解决腾讯webview这种问题的

你是说X5内核那个东西吗?

是的,X5的这个不知道怎么实现,使用上述方法并不行,但是我看微信和QQ上应该是实现了,说明应该是有方法的,所以看你知道这个方法不?

我试试吧,我还没用过x5

@michaellee123
Copy link
Author

腾讯webview这样也不行,有没有解决腾讯webview这种问题的

你是说X5内核那个东西吗?

是的,X5的这个不知道怎么实现,使用上述方法并不行,但是我看微信和QQ上应该是实现了,说明应该是有方法的,所以看你知道这个方法不?

你看看这个代码,我刚才试了,是可以的

import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.scwang.smart.refresh.header.MaterialHeader
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.tencent.smtt.export.external.TbsCoreSettings
import com.tencent.smtt.export.external.extension.proxy.ProxyWebViewClientExtension
import com.tencent.smtt.sdk.QbSdk
import com.tencent.smtt.sdk.WebView
import com.tencent.smtt.sdk.WebViewCallbackClient
import com.tencent.smtt.sdk.WebViewClient


class MainActivity : AppCompatActivity() {

    lateinit var webView: WebView
    lateinit var refreshLayout: SmartRefreshLayout
    val callbackClient = CallbackClient()
    val clientExtension = ClientExtension()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initX5()
        webView = findViewById(R.id.webview)
        refreshLayout = findViewById(R.id.refreshLayout)
        refreshLayout.setRefreshHeader(MaterialHeader(this))
        webView.settings.javaScriptEnabled = true
        webView.settings.domStorageEnabled = true
        webView.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(p0: WebView?, p1: String): Boolean {
                p0?.loadUrl(p1)
                return true
            }

            override fun onPageFinished(p0: WebView?, p1: String?) {
                super.onPageFinished(p0, p1)
                refreshLayout.finishRefresh()
            }
        }
        webView.setWebViewCallbackClient(callbackClient)
        webView.webViewClientExtension = clientExtension
        refreshLayout.setEnableRefresh(false)
        refreshLayout.setOnRefreshListener {
            webView.reload()
        }
        webView.loadUrl("https://www.baidu.com")
    }

    fun initX5() {
        val map = HashMap<String, Any>()
        map[TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER] = true
        map[TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE] = true
        QbSdk.initTbsSettings(map)
    }

    inner class CallbackClient : WebViewCallbackClient {
        override fun invalidate() {}
        override fun onTouchEvent(event: MotionEvent, view: View): Boolean {
            return webView.super_onTouchEvent(event)
        }

        override fun overScrollBy(
            deltaX: Int, deltaY: Int, scrollX: Int,
            scrollY: Int, scrollRangeX: Int, scrollRangeY: Int,
            maxOverScrollX: Int, maxOverScrollY: Int,
            isTouchEvent: Boolean, view: View
        ): Boolean {
            return webView.super_overScrollBy(
                deltaX, deltaY, scrollX, scrollY,
                scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY,
                isTouchEvent
            )
        }

        override fun computeScroll(view: View) {
            webView.super_computeScroll()
        }

        override fun onOverScrolled(
            scrollX: Int, scrollY: Int, clampedX: Boolean,
            clampedY: Boolean, view: View
        ) {
            webView.super_onOverScrolled(scrollX, scrollY, clampedX, clampedY)
        }

        override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int, view: View) {
            webView.super_onScrollChanged(l, t, oldl, oldt)
        }

        override fun dispatchTouchEvent(ev: MotionEvent, view: View): Boolean {
            return webView.super_dispatchTouchEvent(ev)
        }

        override fun onInterceptTouchEvent(ev: MotionEvent, view: View): Boolean {
            return webView.super_onInterceptTouchEvent(ev)
        }
    }

    inner class ClientExtension : ProxyWebViewClientExtension() {

        override fun onTouchEvent(event: MotionEvent, view: View): Boolean {
            if (event.action == MotionEvent.ACTION_DOWN) {
                refreshLayout.setEnableRefresh(false)
            }
            return callbackClient.onTouchEvent(event, view)
        }

        override fun onOverScrolled(
            scrollX: Int, scrollY: Int, clampedX: Boolean,
            clampedY: Boolean, view: View
        ) {
            callbackClient.onOverScrolled(scrollX, scrollY, clampedX, clampedY, view)
            refreshLayout.setEnableRefresh(clampedY)
        }

        //主要代码在上面这两个方法里面,但是下面的方法也不能去掉,必须保留

        override fun onInterceptTouchEvent(ev: MotionEvent, view: View): Boolean {
            return callbackClient.onInterceptTouchEvent(ev, view)
        }

        override fun dispatchTouchEvent(ev: MotionEvent, view: View): Boolean {
            return callbackClient.dispatchTouchEvent(ev, view)
        }

        override fun overScrollBy(
            deltaX: Int, deltaY: Int, scrollX: Int, scrollY: Int,
            scrollRangeX: Int, scrollRangeY: Int,
            maxOverScrollX: Int, maxOverScrollY: Int,
            isTouchEvent: Boolean, view: View
        ): Boolean {
            return callbackClient.overScrollBy(
                deltaX, deltaY, scrollX, scrollY,
                scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent, view
            )
        }

        override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int, view: View) {
            callbackClient.onScrollChanged(l, t, oldl, oldt, view)
        }

        override fun computeScroll(view: View) {
            callbackClient.computeScroll(view)
        }

    }

}

@huaxiaolin
Copy link

腾讯webview这样也不行,有没有解决腾讯webview这种问题的

你是说X5内核那个东西吗?

是的,X5的这个不知道怎么实现,使用上述方法并不行,但是我看微信和QQ上应该是实现了,说明应该是有方法的,所以看你知道这个方法不?

你看看这个代码,我刚才试了,是可以的

import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.scwang.smart.refresh.header.MaterialHeader
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.tencent.smtt.export.external.TbsCoreSettings
import com.tencent.smtt.export.external.extension.proxy.ProxyWebViewClientExtension
import com.tencent.smtt.sdk.QbSdk
import com.tencent.smtt.sdk.WebView
import com.tencent.smtt.sdk.WebViewCallbackClient
import com.tencent.smtt.sdk.WebViewClient


class MainActivity : AppCompatActivity() {

    lateinit var webView: WebView
    lateinit var refreshLayout: SmartRefreshLayout
    val callbackClient = CallbackClient()
    val clientExtension = ClientExtension()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initX5()
        webView = findViewById(R.id.webview)
        refreshLayout = findViewById(R.id.refreshLayout)
        refreshLayout.setRefreshHeader(MaterialHeader(this))
        webView.settings.javaScriptEnabled = true
        webView.settings.domStorageEnabled = true
        webView.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(p0: WebView?, p1: String): Boolean {
                p0?.loadUrl(p1)
                return true
            }

            override fun onPageFinished(p0: WebView?, p1: String?) {
                super.onPageFinished(p0, p1)
                refreshLayout.finishRefresh()
            }
        }
        webView.setWebViewCallbackClient(callbackClient)
        webView.webViewClientExtension = clientExtension
        refreshLayout.setEnableRefresh(false)
        refreshLayout.setOnRefreshListener {
            webView.reload()
        }
        webView.loadUrl("https://www.baidu.com")
    }

    fun initX5() {
        val map = HashMap<String, Any>()
        map[TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER] = true
        map[TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE] = true
        QbSdk.initTbsSettings(map)
    }

    inner class CallbackClient : WebViewCallbackClient {
        override fun invalidate() {}
        override fun onTouchEvent(event: MotionEvent, view: View): Boolean {
            return webView.super_onTouchEvent(event)
        }

        override fun overScrollBy(
            deltaX: Int, deltaY: Int, scrollX: Int,
            scrollY: Int, scrollRangeX: Int, scrollRangeY: Int,
            maxOverScrollX: Int, maxOverScrollY: Int,
            isTouchEvent: Boolean, view: View
        ): Boolean {
            return webView.super_overScrollBy(
                deltaX, deltaY, scrollX, scrollY,
                scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY,
                isTouchEvent
            )
        }

        override fun computeScroll(view: View) {
            webView.super_computeScroll()
        }

        override fun onOverScrolled(
            scrollX: Int, scrollY: Int, clampedX: Boolean,
            clampedY: Boolean, view: View
        ) {
            webView.super_onOverScrolled(scrollX, scrollY, clampedX, clampedY)
        }

        override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int, view: View) {
            webView.super_onScrollChanged(l, t, oldl, oldt)
        }

        override fun dispatchTouchEvent(ev: MotionEvent, view: View): Boolean {
            return webView.super_dispatchTouchEvent(ev)
        }

        override fun onInterceptTouchEvent(ev: MotionEvent, view: View): Boolean {
            return webView.super_onInterceptTouchEvent(ev)
        }
    }

    inner class ClientExtension : ProxyWebViewClientExtension() {

        override fun onTouchEvent(event: MotionEvent, view: View): Boolean {
            if (event.action == MotionEvent.ACTION_DOWN) {
                refreshLayout.setEnableRefresh(false)
            }
            return callbackClient.onTouchEvent(event, view)
        }

        override fun onOverScrolled(
            scrollX: Int, scrollY: Int, clampedX: Boolean,
            clampedY: Boolean, view: View
        ) {
            callbackClient.onOverScrolled(scrollX, scrollY, clampedX, clampedY, view)
            refreshLayout.setEnableRefresh(clampedY)
        }

        //主要代码在上面这两个方法里面,但是下面的方法也不能去掉,必须保留

        override fun onInterceptTouchEvent(ev: MotionEvent, view: View): Boolean {
            return callbackClient.onInterceptTouchEvent(ev, view)
        }

        override fun dispatchTouchEvent(ev: MotionEvent, view: View): Boolean {
            return callbackClient.dispatchTouchEvent(ev, view)
        }

        override fun overScrollBy(
            deltaX: Int, deltaY: Int, scrollX: Int, scrollY: Int,
            scrollRangeX: Int, scrollRangeY: Int,
            maxOverScrollX: Int, maxOverScrollY: Int,
            isTouchEvent: Boolean, view: View
        ): Boolean {
            return callbackClient.overScrollBy(
                deltaX, deltaY, scrollX, scrollY,
                scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent, view
            )
        }

        override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int, view: View) {
            callbackClient.onScrollChanged(l, t, oldl, oldt, view)
        }

        override fun computeScroll(view: View) {
            callbackClient.computeScroll(view)
        }

    }

}

这种方法可以,但是还是存在X5内核未加载成功的情况下失效的问题,因为X5内核的加载在首次安装的时候,多数情况下是失败的,在这种情况下这种方法就有失效了,要不加个QQ吧 ,578469246 。

@michaellee123
Copy link
Author

@huaxiaolin 没加载成功的就自己看X5的文档了吧,我这个方法其实就是在over scroll的时候去给它设置成可以下拉,一共就两句代码有用,只是需要找一下相应的设置方法就行了。

@h-zhouwenjun
Copy link

网页里面弹窗滚动冲突怎么处理

@michaellee123
Copy link
Author

你是说弹窗里面用了scroll之类的控件那种吗?

@594238813
Copy link

594238813 commented Dec 15, 2022

为什么我 下拉刷新 ,X5 reload() 之后

onProgressChanged 的 newProgress 进度 一直在 70
shouldOverrideUrlLoading(..) 就不回调了
唉~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants