2

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!

skyguy126
  • 457
  • 1
  • 5
  • 17

1 Answers1

3

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
         }
     }
}
DarkLeafyGreen
  • 69,338
  • 131
  • 383
  • 601
  • it did work but I am getting the speed of the scroll change, how can I make it so that the refresh indicator should not show until a new touch happens. – skyguy126 Sep 11 '16 at 20:48
  • 2
    @skyguy126 not speed but the change in coordinates. Make use of onScrollStateChanged https://developer.android.com/reference/android/support/v7/widget/RecyclerView.OnScrollListener.html#onScrollStateChanged(android.support.v7.widget.RecyclerView, int). I changed the code and the gist. – DarkLeafyGreen Sep 11 '16 at 20:54
  • almost there... calling this `this.swipeRefreshLayout.setEnabled(false);` seems to have no effect on the refresh. Any idea what I might be doing wrong. – skyguy126 Sep 11 '16 at 21:08
  • Are you sure it is called? What do you mean with "no effect"? setEnabled(false) should disable the gesture. – DarkLeafyGreen Sep 11 '16 at 21:11
  • Yes it is being called I set up some logging and I can see the log messages coming up. Here is my code: https://gist.github.com/skyguy126/a4d8b842e6406a98a03a6682cbe1dbcc No "effect" as in the gesture still works – skyguy126 Sep 11 '16 at 21:12
  • 2
    @skyguy126 If the gesture still works, setEnabled(false) should not have been called. Maybe you have this problem due to the fact that the list view is not a direct child of swipe layout, but I am not sure, check out http://stackoverflow.com/questions/25270171/scroll-up-does-not-work-with-swiperefreshlayout-in-listview – DarkLeafyGreen Sep 11 '16 at 21:25
  • I think `setEnabled` is not updating the layout until I release the scroll. Maybe it is a different issue, but thanks for your help so far! – skyguy126 Sep 11 '16 at 21:31