skyguy126 skyguy126 - 2 months ago 31
Android Question

Android SwipeRefreshLayout with RecyclerView

Here is my code setup:

Currently I have a Main Activity which then creates a spawns a fragment with

getSupportFragmentManager()
. The Fragment contains a
RecyclerView
(for a card view) as defined in the xml below:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity" >

<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none" />

</RelativeLayout>


And this is the layout of my main activity:

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

...

<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/activity_main_swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</android.support.v4.widget.SwipeRefreshLayout>

</LinearLayout>


The main activity instantiates the fragment which then creates its own
RecyclerView, LinearLayoutManager, and Adapter
without any connections to the main activity.

The main activity creates the SwipeRefreshLayout as seen in the xml above.

The problem I have is the when I scroll up in my activity, once the list cannot scroll any further up the refresh indicator pulls down if I keep swiping down and refreshes. I don't want the indicator to pull down until I release the current touch and pull down again.

Since I cannot directly access the recycler view from my activity to add an OnScrollListener and enable and disable the SwipeRefreshLayout programmatically, how should I go about solving this?

All answers appreciated!

Answer

Since I cannot directly access the recycler view from my activity to add an OnScrollListener and enable and disable the SwipeRefreshLayout programmatically, how should I go about solving this?

Yes, you can!

First implement RecyclerView.OnScrollListener so that your fragment can listen to scroll events. To do so you have to subclass RecyclerView.OnScrollListener: https://gist.github.com/ArtworkAD/ae6241d60282a54adfa22d28cddb48ae

The next step is to delegate the scroll events to the hosting activity to make changes to the swipe layout. Your fragment may have following additions:

public class SomeFragment extends Fragment implements OnScrollStateListener {

    public interface ScrollEventListener {
        void onScroll(int dx, int dy)
        void onScrollStateChanged(int state)
    }

    ScrollEventListener scrollEventListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Give the recycler view a scroll listener
        recyclerView.addOnScrollListener(new DefaultRecycleViewScrollListener(this));
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        // delegate the event to the listener
        scrollEventListener.onScrollStateChanged(newState);
    }

    @Override
    public void onScrolled(int dx, int dy) {
        // delegate the event to the listener
        scrollEventListener.onScrolled(dx, dy);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        // activity should implement the interface
        if (context instanceof ScrollEventListener) {
          scrollEventListener = (ScrollEventListener) context;
        }
    }
}

Make sure to implement ScrollEventListener in your activity to receive scroll events.

public class SomeActivity extends Activity implements SomeFragment.ScrollEventListener {

     @Override
     public void onScroll(int dx, int dy) {
         // access swipe layout here
     }

     @Override
     public void void onScrollStateChanged(int state){
         if (state == SCROLL_STATE_DRAGGING) {
             // disable swipe
         } else {
             // enable
         }
     }
}