Overscroll effect doesn't appear in my recyclerview inside swiperefreshlayout

3.8k Views Asked by At

I have a fragment that contain a SwipeRefreshLayour with a RecyclerView inside.

This recyclerView doesn't show overscroll effects. I tried a lot of things like use this:

 android:isScrollContainer="true"
 android:overScrollMode="always"

Custom color via styles doesn't work

fadingEdge, fadingEdgeLengh, requiresFadingEdge...

Swipe to refresh is working and it shows this:

enter image description here

I don't get this:

enter image description here

2

There are 2 best solutions below

13
On

In my implementation of this feature, (the over-scroll is working on both top and bottom), I have my layout like this:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<...<custom view>...SwipeRefreshWrapper
    android:id="@+id/swiperefresh_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RecyclerView
            android:id="@+id/video_recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <include layout="@layout/include_video_list_empty_view"/>
        <include layout="@layout/include_watchlist_empty_view"/>

    </FrameLayout>
<SwipeRefreshWrapper>

And my SwipeRefreshWrapper implementation is as follows:

/**
* This Class ensures that a SwipeRefreshLayout will only refresh if the
* list it wraps cannot scroll up anymore, (that it is at the top). Otherwise
* when the user attempts to scroll up from the middle of the list, the refresh
* will trigger. This is necessary for custom List implementations, (or
* RecyclerViews), only.
*/
public class SwipeRefreshWrapper extends SwipeRefreshLayout {
     private ScrollResolver mScrollResolver;

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

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

     public void setScrollResolver(ScrollResolver scrollResolver) {
         mScrollResolver = scrollResolver;
     }

     @Override
     public boolean canChildScrollUp() {
         if(mScrollResolver != null){
             return mScrollResolver.canScrollUp();
         } else {
             return super.canChildScrollUp();
         }
     }

     public static interface ScrollResolver{
         public boolean canScrollUp();
     }
}

Then in my Fragment I setup the SwipeRefreshLayout:

 /**
 * Initializes PullToRefresh handler
 */
private void initPullToRefresh() {
    mSwipeRefreshLayout = (SwipeRefreshWrapper) mView.findViewById(R.id.swiperefresh_layout);
    mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary, R.color.colorAccent);

    mSwipeRefreshLayout.setScrollResolver(new SwipeRefreshWrapper.ScrollResolver() {
        @Override
        public boolean canScrollUp() {
            return mVideoRecycler.canScrollVertically(-1);
        }
    });

    mSwipeRefreshLayout.setOnRefreshListener(...)
}
0
On

I just solved it by overwriting the SwipeRefreshLayout and using it instead of the default implementation:

import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout

class SwipeRefreshLayoutWithRecyclerViewOverscroll : SwipeRefreshLayout {

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    override fun onStartNestedScroll(child: View, target: View, nestedScrollAxes: Int): Boolean =
        (child.canScrollVertically(1) && super.onStartNestedScroll(child, target, nestedScrollAxes))

}

I'm using a RecyclerView that is a linear vertical list and child.canScrollVertically(1) checks wether this list is currently at the very bottom. If it is at the bottom of the list onStartNestedScroll returns false, allowing the RecyclerView to handle the pull up motion of the user so that an overscroll effect is shown.

NOTE: This only shows the bottom edge overscroll and not the top one, because I don't want to see the pull-to-refresh animation together with the top overscroll edge.