How to implement Android Pull-to-Refresh

AndroidListviewAndroid ListviewPull to-Refresh

Android Problem Overview


In Android applications such as Twitter (official app), when you encounter a ListView, you can pull it down (and it will bounce back when released) to refresh the content.

I wonder what is the best way, in your opinion, to implement that?

Some possibilities I could think of:

  1. An item on top of the ListView - however I don't think scrolling back to item position 1 (0-based) with animation on the ListView is an easy task.
  2. Another view outside the ListView - but I need to take care of moving the ListView position down when it is pulled, and I'm not sure if we can detect if the drag-touches to the ListView still really scroll the items on the ListView.

Any recommendations?

P.S. I wonder when the official Twitter app source code is released. It has been mentioned that it will be released, but 6 months has passed and we haven't heard about it since then.

Android Solutions


Solution 1 - Android

Finally, Google released an official version of the pull-to-refresh library!

It is called SwipeRefreshLayout, inside the support library, and the documentation is here:

  1. Add SwipeRefreshLayout as a parent of view which will be treated as a pull to refresh the layout. (I took ListView as an example, it can be any View like LinearLayout, ScrollView etc.)

     <android.support.v4.widget.SwipeRefreshLayout
         android:id="@+id/pullToRefresh"
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
         <ListView
             android:id="@+id/listView"
             android:layout_width="match_parent"
             android:layout_height="match_parent"/>
     </android.support.v4.widget.SwipeRefreshLayout>
    
  2. Add a listener to your class

     protected void onCreate(Bundle savedInstanceState) {
         final SwipeRefreshLayout pullToRefresh = findViewById(R.id.pullToRefresh);
         pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
             @Override
             public void onRefresh() {
                 refreshData(); // your code
                 pullToRefresh.setRefreshing(false);
             }
         });
     }
    

You can also call pullToRefresh.setRefreshing(true/false); as per your requirement.

UPDATE

Android support libraries have been deprecated and have been replaced by AndroidX. The link to the new library can be found here.

Also, you need to add the following dependency to your project:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

OR

You can go to Refactor>>Migrate to AndroidX and Android Studio will handle the dependencies for you.

Solution 2 - Android

I've made an attempt to implement a pull to refresh component, it's far from complete but demonstrates a possible implementation, https://github.com/johannilsson/android-pulltorefresh.

Main logic is implemented in PullToRefreshListView that extends ListView. Internally it controls the scrolling of a header view using smoothScrollBy (API Level 8). The widget is now updated with support for 1.5 and later, please read the README for 1.5 support though.

In your layouts you simply add it like this.

<com.markupartist.android.widget.PullToRefreshListView
    android:id="@+id/android:list"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />

Solution 3 - Android

I've also implemented a robust, open source, easy to use and highly customizable PullToRefresh library for Android. You can replace your ListView with the PullToRefreshListView as described in the documentation on the project page.

https://github.com/erikwt/PullToRefresh-ListView

Solution 4 - Android

The easiest way i think is as provided by the android support library:

android.support.v4.widget.SwipeRefreshLayout;

once that is imported then you can have your layout defined as follows:

  <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh"
        android:layout_height="match_parent"
        android:layout_width="match_parent">
    <android.support.v7.widget.RecyclerView
        xmlns:recycler_view="http://schemas.android.com/apk/res-auto"
        android:id="@android:id/list"
        android:theme="@style/Theme.AppCompat.Light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/button_material_light"
        >

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

I assume that you use recycler view instead of listview. However, listview still works so you just need to replace recyclerview with listview and update the references in the java code (Fragment).

In your activity fragment, you first implement the interface, SwipeRefreshLayout.OnRefreshListener: i,e

public class MySwipeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
private SwipeRefreshLayout swipeRefreshLayout;

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_item, container, false);
        swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.refresh);
        swipeRefreshLayout.setOnRefreshListener(this);
}


 @Override
  public void onRefresh(){
     swipeRefreshLayout.setRefreshing(true);
     refreshList();
  }
  refreshList(){
    //do processing to get new data and set your listview's adapter, maybe  reinitialise the loaders you may be using or so
   //when your data has finished loading, cset the refresh state of the view to false
   swipeRefreshLayout.setRefreshing(false);
     
   }
}

Hope this helps the masses

Solution 5 - Android

In this link, you can find a fork of the famous PullToRefresh view that has new interesting implementations like PullTorRefreshWebView or PullToRefreshGridView or the possibility to add a PullToRefresh on the bottom edge of a list.

https://github.com/chrisbanes/Android-PullToRefresh

And the best of it is that work perfect in Android 4.1 (the normal PullToRefresh doesn't work )

Solution 6 - Android

To implement android Pull-to-Refresh try this piece of code,

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

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>

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

Activity class:

ListView lv = (ListView) findViewById(R.id.lv);
SwipeRefreshLayout pullToRefresh = (SwipeRefreshLayout) findViewById(R.id.pullToRefresh);


lv.setAdapter(mAdapter);

pullToRefresh.setOnRefreshListener(new OnRefreshListener() {
		
		@Override
		public void onRefresh() {
			// TODO Auto-generated method stub
			
			refreshContent();
			
		}
	});



private void refreshContent(){ 
	 
	 new Handler().postDelayed(new Runnable() {
	        @Override public void run() {
	        	pullToRefresh.setRefreshing(false);
	        }
	    }, 5000);
	 
 }

Solution 7 - Android

I have very easy way to do this but now sure its the foolproof way There is my code PullDownListView.java

package com.myproject.widgets;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

/**
 * @author Pushpan
 * @date Nov 27, 2012
 **/
public class PullDownListView extends ListView implements OnScrollListener {

	private ListViewTouchEventListener mTouchListener;
	private boolean pulledDown;

	public PullDownListView(Context context) {
		super(context);
		init();
	}

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

	public PullDownListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	private void init() {
		setOnScrollListener(this);
	}

	private float lastY;

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		if (ev.getAction() == MotionEvent.ACTION_DOWN) {
			lastY = ev.getRawY();
		} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
			float newY = ev.getRawY();
			setPulledDown((newY - lastY) > 0);
			postDelayed(new Runnable() {
				@Override
				public void run() {
					if (isPulledDown()) {
						if (mTouchListener != null) {
							mTouchListener.onListViewPulledDown();
							setPulledDown(false);
						}
					}
				}
			}, 400);
			lastY = newY;
		} else if (ev.getAction() == MotionEvent.ACTION_UP) {
			lastY = 0;
		}
		return super.dispatchTouchEvent(ev);
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		setPulledDown(false);
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
	}

	public interface ListViewTouchEventListener {
		public void onListViewPulledDown();
	}

	public void setListViewTouchListener(
			ListViewTouchEventListener touchListener) {
		this.mTouchListener = touchListener;
	}

	public ListViewTouchEventListener getListViewTouchListener() {
		return mTouchListener;
	}

	public boolean isPulledDown() {
		return pulledDown;
	}

	public void setPulledDown(boolean pulledDown) {
		this.pulledDown = pulledDown;
	}
}

You just need to implement ListViewTouchEventListener on your activity where you want to use this ListView and set the listener

I have it implemented in PullDownListViewActivity

package com.myproject.activities;

import android.app.Activity;
import android.os.Bundle;

/**
 * @author Pushpan
 *
 */
public class PullDownListViewActivity extends Activity implements ListViewTouchEventListener {

	private PullDownListView listView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		listView = new PullDownListView(this);
		setContentView(listView);
		listView.setListViewTouchListener(this);
		
		//setItems in listview
	}
	
	public void onListViewPulledDown(){
		Log.("PullDownListViewActivity", "ListView pulled down");
	}
}

It works for me :)

Solution 8 - Android

Nobody have mention the new type of "Pull to refresh" which shows on top of the action bar like in the Google Now or Gmail application.

There is a library ActionBar-PullToRefresh which works exactly the same.

Solution 9 - Android

Note there are UX issues to contend with when implementing on Android and WP.

"A great indicator for why designers/devs should not implement pull-to-refresh in the style iOS apps do is how Google and their teams never use pull-to-refresh on Android while they do use it in iOS. "

https://plus.google.com/109453683460749241197/posts/eqYxXR8L4eb

Solution 10 - Android

If you don't want your program to look like an iPhone program that is force fitted into Android, aim for a more native look and feel and do something similar to Gingerbread:

alt text

Solution 11 - Android

I've written a pull to refresh component here: https://github.com/guillep/PullToRefresh It works event if the list does not have items, and I've tested it on >=1.6 android phones.

Any suggestion or improvement is appreciated :)

Solution 12 - Android

I think the best library is : https://github.com/chrisbanes/Android-PullToRefresh.

Works with:

ListView
ExpandableListView
GridView
WebView
ScrollView
HorizontalScrollView
ViewPager

Solution 13 - Android

We should first know what is Pull to refresh layout in android . we can call pull to refresh in android as swipe-to-refresh. when you swipe screen from top to bottom it will do some action based on setOnRefreshListener.

Here's tutorial that demonstrate about how to implement android pull to refresh. I hope this helps.

Solution 14 - Android

To get the latest Lollipop Pull-To Refresh:

  1. Download the latest Lollipop SDK and Extras/Android support library
  2. Set Project's Build Target to Android 5.0 (otherwise support package can have errors with resources)
  3. Update your libs/android-support-v4.jar to 21st version
  4. Use android.support.v4.widget.SwipeRefreshLayout plus android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

Detailed guide could be found here: http://antonioleiva.com/swiperefreshlayout/

Plus for ListView I recommend to read about canChildScrollUp() in the comments ;)

Solution 15 - Android

Very interesting Pull-to-Refresh by Yalantis. Gif for iOS, but you can check it :)

<com.yalantis.pulltorefresh.library.PullToRefreshView
android:id="@+id/pull_to_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
    android:id="@+id/list_view"
    android:divider="@null"
    android:dividerHeight="0dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Solution 16 - Android

Those who are looking to implement pull to refresh functionality for RecyclerView can following my simple tutorial How to implement Pull To Refresh for RecyclerView in Android.

Libraries To Import

implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'

XML Code

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:id="@+id/swipe_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

Activity JAVA Code

import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.os.Bundle;
import android.os.Handler;

public class MainActivity extends AppCompatActivity {

private SwipeRefreshLayout swipeRefreshLayout;

...

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        ...
        swipeRefreshLayout = findViewById(R.id.swipe_layout);
        initializeRefreshListener();
}

    void initializeRefreshListener() {

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                // This method gets called when user pull for refresh,
                // You can make your API call here,
                // We are using adding a delay for the moment
                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if(swipeRefreshLayout.isRefreshing()) {
                            swipeRefreshLayout.setRefreshing(false);
                        }
                    }
                }, 3000);
            }
        });
    }

Solution 17 - Android

Add this in your layout

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

Now simply add these below lines in your code

 mSwipeRefreshLayout.setOnRefreshListener(() -> {

       // your refresh code here

    });

You are all done

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRandy Sugianto &#39;Yuku&#39;View Question on Stackoverflow
Solution 1 - AndroidRandy Sugianto 'Yuku'View Answer on Stackoverflow
Solution 2 - AndroidJohan Berg NilssonView Answer on Stackoverflow
Solution 3 - AndroidErikView Answer on Stackoverflow
Solution 4 - AndroidAkahView Answer on Stackoverflow
Solution 5 - AndroidAracemView Answer on Stackoverflow
Solution 6 - AndroidmaniView Answer on Stackoverflow
Solution 7 - AndroidPushpanView Answer on Stackoverflow
Solution 8 - AndroidtomrozbView Answer on Stackoverflow
Solution 9 - AndroiduobroinView Answer on Stackoverflow
Solution 10 - AndroidLie RyanView Answer on Stackoverflow
Solution 11 - AndroidGuille PolitoView Answer on Stackoverflow
Solution 12 - AndroidJossy PaulView Answer on Stackoverflow
Solution 13 - AndroidHasan RazaView Answer on Stackoverflow
Solution 14 - AndroidgoRGonView Answer on Stackoverflow
Solution 15 - AndroidedbaevView Answer on Stackoverflow
Solution 16 - AndroidAsad Ali ChoudhryView Answer on Stackoverflow
Solution 17 - AndroidAhsan MalikView Answer on Stackoverflow