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:
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. 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.
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:
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.)
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.
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
The widget is now updated with support for 1.5 and later, please read the README for 1.5 support though.
smoothScrollBy
(API Level 8).
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"
/>
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
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
setRefreshing
: "Do not call this when refresh is triggered by a swipe gesture" as described in developer.android.com/reference/android/support/v4/widget/…
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 )
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);
}
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 :)
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.
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
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:
https://i.stack.imgur.com/SPejA.png
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 :)
I think the best library is : https://github.com/chrisbanes/Android-PullToRefresh.
Works with:
ListView
ExpandableListView
GridView
WebView
ScrollView
HorizontalScrollView
ViewPager
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.
To get the latest Lollipop Pull-To Refresh:
Download the latest Lollipop SDK and Extras/Android support library Set Project's Build Target to Android 5.0 (otherwise support package can have errors with resources) Update your libs/android-support-v4.jar to 21st version 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 ;)
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" />
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);
}
});
}
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
Success story sharing