Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwipeRefreshLayout blocks onClickCallback of item in nested RecyclerView

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.

like image 485
Viktor Lund Avatar asked Oct 21 '25 05:10

Viktor Lund


1 Answers

I have been experiencing the same issue. I did have a ConstraintLayout wrapping the SwipeRefreshLayout. When I removed the ConstraintLayout (replaced it with LinearLayout) the issue fixed. Hope that helps. I have no idea why it is working.

like image 186
Katie B Avatar answered Oct 23 '25 20:10

Katie B