Zapnologica
Zapnologica

Reputation: 22566

SwipeRefreshLayout inside ViewPager

I have an activity that consists of a Toolbar and a view pager. Its layout is as follows:

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

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="112dp"
    android:layout_gravity="bottom"
    tools:context=".Rhino68PanelActivity" />

<LinearLayout
    android:id="@+id/toolbarContainer"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <include
        android:id="@+id/app_bar"
        layout="@layout/app_bar" />

    <include
        android:id="@+id/tap_strip"
        layout="@layout/tab_strip" />

</LinearLayout>

I then load two fragments into the view pager. Each fragment contains its own SwipeRefreshLayout. I will show one fragments layout:

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="12"
    tools:context=".Rhino68PanelActivity$DummySectionFragment">
    ...        
  <android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView_panel_status"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipToPadding="false" />

</LinearLayout>

Now when I run the activity it seems to work. However I have noticed that is I slide horizontally (ie to go to the next tab). It triggers the swipeRefreshLayout OnRefreshListener

     mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                mSwipeRefreshLayout.setRefreshing(true);
                DoUpdate();
            }
        });

I am also experiencing odd visual behavior when I do try and do a refresh. The loading sign (spinning circle) often doesn't show, and it sometimes shows but stays small. I'm not sure if this is also a cause of the two views conflicting with one another.

Is there some way that I can fix this issue. I'm not to sure how. Maybe by limiting the SwipeRefreshLayout to only listen for vertical swipes?

Any suggestions will be greatly appreciated.

Upvotes: 7

Views: 5768

Answers (2)

sergej shafarenka
sergej shafarenka

Reputation: 20426

I also had this stupid issue. It appears to be a bug in SwipeRefreshLayout. As a workaround I had to remove all its child views in Fragment.onDestroyView() method.

public SwipeRefreshLayout mSwipeRefreshLayout;
...

@Override public void onDestroyView() {
    mSwipeRefreshLayout.removeAllViews();
    super.onDestroyView();
}

Upvotes: 3

The Finest Artist
The Finest Artist

Reputation: 3189

It is because there is a bug in SwipeRefreshLayout! The bug is "onRefresh doesn't work properly if the onMeasure is not called" You should extends SwipeRefreshLayout like this!

public class SwipeRefreshLoading extends SwipeRefreshLayout {
    public SwipeRefreshLoading(Context context) {
        super(context, null);
    }

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

    private boolean mMeasured = false;
    private boolean mPreMeasureRefreshing = false;

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!mMeasured) {
            mMeasured = true;
            setRefreshing(mPreMeasureRefreshing);
        }
    }


    @Override
    public void setRefreshing(boolean refreshing) {
        if (mMeasured) {
            super.setRefreshing(refreshing);
        } else {
            mPreMeasureRefreshing = refreshing;
        }
    }
}

Upvotes: 1

Related Questions