Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 475
Zapnologica Avatar asked May 24 '15 10:05

Zapnologica


2 Answers

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();
}
like image 200
sergej shafarenka Avatar answered Sep 28 '22 16:09

sergej shafarenka


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;
        }
    }
}
like image 20
The Finest Artist Avatar answered Sep 28 '22 16:09

The Finest Artist