android – SwipeRefreshLayout blocks onClickCallback of item in nested RecyclerView-ThrowExceptions

Exception or error:

I have a SwipeRefreshLayout with a nested RecyclerView. Each item in the recycler view essentially is a CardView with an onClickHandler attached. I have an issue where my clickHandler is not called if the recycler view is scrolled to the very top. If I scroll one px down I can click on things.

After adding printout statements on touch events and on click events it seems as if the swipe refresh layout will also intercept the touch event and setTargetOffsetTopAndBottom. This calls requestLayout which eventually seems to lead to an ACTION_CANCEL event. If I scroll down the recycler view 1px canChildScrollUp() will return true and stop the requestLayout call by the SwipRefreshLayout.

// SwipeRefreshLayout.java
public boolean onInterceptTouchEvent(MotionEvent ev) {
    ...
    if (!isEnabled() || mReturningToStart || canChildScrollUp()
            || mRefreshing || mNestedScrollInProgress) {
        // Fail fast if we're not in a state where a swipe is possible
        return false;
    }
    ...
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop());
            mActivePointerId = ev.getPointerId(0);
            mIsBeingDragged = false;

            pointerIndex = ev.findPointerIndex(mActivePointerId);
            if (pointerIndex < 0) {
                return false;
            }
            mInitialDownY = ev.getY(pointerIndex);
            break;
    ...

Layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/ticket_wallet_refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/ticket_wallet_recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:itemCount="3"
        tools:listheader="@layout/ticket_header_item"
        tools:listitem="@layout/active_ticket_item" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

ViewHolder

sealed class FooViewHolder(view: View) : RecyclerView.ViewHolder(view) {

    abstract fun bind(item: WalletItem)

    class ActiveFooViewHolder(
        view: View,
        private val remainingTimeFormatter: RemainingTimeFormatter,
        private val callback: (Int) -> Unit
    ) : FooViewHolder(view) {

        init {
            view.setOnClickListener {
                callback(adapterPosition)
            }
   ...

My compile target is Android API lvl 29.

How to solve:

Leave a Reply

Your email address will not be published. Required fields are marked *