Android WebView SwipeRefreshLayout and draggable elements

  android, android-webview

I’ve wrapped a WebView in a androidx.swiperefreshlayout.widget.SwipeRefreshLayout:

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:id="@+id/swipe_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
        <WebView
            android:id="@+id/webview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:nestedScrollingEnabled="false"
            tools:layout_editor_absoluteX="201dp"
            tools:layout_editor_absoluteY="359dp" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

It works pretty well: Pulling down far enough triggers the callback to reload the page.

However, we have elements on the page that are drag-/sortable.
Unfortunately, dragging is being interpreted as scrolling as well — and therefore also triggering the SwipeRefresh.

This is surprising to me because I just implemented the same thing in iOS with WKWebView. While that had its own share of surprises (handling cookies…), this actually worked like I would have expected: The SwipeRefreshLayout is coupled to actual scroll events on the page, not any touch-and-drag-event.

See this Gif as an example of the issue:

Issues with sorting items and SwipeRefreshLayout

I find it very surprising that I absolutely can’t find anything about this anywhere. Surely we can’t be the first people to encounter this issue.

I even understand why it occurs conceptually. I fail to be able to come up with a good solution, though.

Also, I have no clue about Java and/or Kotlin and the Android SDK. I have extensive experience with Flutter, but I’m out of my element here.

Any help is greatly appreciated.

For completeness sake, here’s my MainActivity.kt:

class MainActivity : AppCompatActivity() {

    private var swipeRefreshLayout: SwipeRefreshLayout? = null
    private lateinit var webView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        swipeRefreshLayout = findViewById<SwipeRefreshLayout>(R.id.swipe_layout);
        swipeRefreshLayout!!.isEnabled = false;

        webView = findViewById<View>(R.id.webview) as WebView

        webView.settings.javaScriptEnabled = true;
        webView.settings.domStorageEnabled = true;
        webView.settings.setSupportMultipleWindows(true);
        webView.settings.javaScriptCanOpenWindowsAutomatically = true;

        webView.viewTreeObserver.addOnScrollChangedListener(OnScrollChangedListener {
            val scrollY: Int = webView.scrollY

            if(scrollY == 0) {
                swipeRefreshLayout!!.isEnabled = true;
            } else {
                swipeRefreshLayout!!.isEnabled = false;
            }
        })

        webView.webViewClient = object : WebViewClient() {
            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                // ...
            }
        }

        webView.webChromeClient = object : WebChromeClient() {
             override fun onCreateWindow(
                 view: WebView,
                 dialog: Boolean,
                 userGesture: Boolean,
                 resultMsg: Message
             ): Boolean {
                 // ...
            }
        }

        initializeRefreshListener();

        webView.loadUrl("http://abc123.xyz789");
    }

    private fun initializeRefreshListener() {
        swipeRefreshLayout!!.setOnRefreshListener {
            webView.loadUrl(webView.url!!);
            val x = swipeRefreshLayout
            if(x != null) {
                if (x.isRefreshing) {
                    x.isRefreshing = false
                }
            }
        }
    }
}

Source: Android Questions

LEAVE A COMMENT