ChatGPT解决这个技术问题 Extra ChatGPT

How to implement Android Pull-to-Refresh

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.

Is this functionality can be implemented in a dynamically created TableLayout. Please Help.....
github.com/fruitranger/PulltorefreshListView is a another implementation of mine. Smooth and multi-touch support.
Related: “Pull-to-refresh”: an anti UI pattern on Android is an article arguing that this UI isn't something that should be used on Android and sparked a lot of discussion about its appropriateness.
Somebody should let Google know because the latest version of Gmail for Android uses this "anti pattern".
Pull to refresh is (and has been for a while) a standard adopted pattern in iOS and Android and it's very natural, so this anti-pattern discussion is outdated. Users will expect to see it and behave as such.

M
MSpeed

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.) 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.


can I use a ProgressBar instead of Color Scheme on SwipeRefreshLayout?
Apr 1 '14 - and that was not a joke
J
Johan Berg Nilsson

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"
    />

Hi johan, I have downloaded your sample code. It is worked in android 2.2 device but not worked in 2.1 device. I think because it used smoothScrollBy method which only available in 2.2 or later, is correct? And do you have any idea to implement this effect into 2.1 or earlier version? Thanks
Yes that's correct as I stated in the answer smoothScrollBy was introduces in API Level 8 (2.2). I haven't figured out a proper way to implement it for other versions yet, but it guess it should be possible to port the implementation of smoothScrollBy but I guess that discussion should be kept at the project site and not on stack overflow?
Is it on purpose that the id is @+id/android:list and not @android:id/list, it looks weird? The project throws an inflation error here on my side, I'm currently checking on that...
This is the best library for pull to refresh I have found..github.com/chrisbanes/Android-PullToRefresh. It works with ListViews, GridViews and Webviews. Also has Pull up to refresh pattern implemented.
How do I add the project into library folder while working on Intellij Idea? Can anybody help me?
E
Erik

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


I tried all of the implementations listed here and yours is the best, in terms of a simple/pure/smooth pull to refresh implementation (no tap to refresh weirdness like Johan's). Thanks!
Can this replace a standard ListView to work with ListActivity, ListFragment and so on?
Yes, just give the PullToRefreshListView the right id. In XML: android:id="@android:id/list"
this is absolutely awesome! google brought me here, and looking through the examples, your's looks the easiest to implement. bravo and thank you sir!
Very sensibly designed component, nice and simple. This should definitely be the accepted answer.
A
Akah

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


It works well. Though, one thing regarding setRefreshing: "Do not call this when refresh is triggered by a swipe gesture" as described in developer.android.com/reference/android/support/v4/widget/…
A
Aracem

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 )


A big comment at the top of the readme indicates: THIS PROJECT IS NO LONGER BEING MAINTAINED. Anyway, this lib is the best one I have seen so far! Great work!
Just because it's no longer being maintained, doesn't mean it's not good. Still use it for all my pull to refresh needs :)
m
mani

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);

 }

P
Pushpan

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 :)


t
tomrozb

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.


Q
QED

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


I know this is over a year old but the Gmail app does use pull-to-refresh. However it's not exactly the same in terms of the UI, the list does not scroll down, rather a new view shows at the top of the screen.
L
Lie Ryan

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


@Rob: I meant having the orange shadow on the top of the list when you overpull, instead of having the list bounce back like on iPhone. This is meant as a comment (not answer), but comments can't have images.
Ahh, sorry, great Idea. I haven't played with gingerbread yet, so hadn't seen the effect. Still waiting for google to roll it to the nexus one.
I have Gingerbread and the orange glow works great when a list is static. But the pull-down-refresh is a great UI mecanism to refresh a dynamic list. Although it is prevalent in iOS world, it's a UI trick that doesn't feel wierd in Android ecosystem. I strongly suggest you check it out in the official Twitter app. :)
The native behaviour here is to indicate that you have reached the end of a list. Taking this, and performing a refresh is identically non native as you are not doing what the platform does. This means you are more likely to surprise the user. I certainly wouldn't expect nor want a refresh just because I got to the end of a list. Pull down to refresh is a lot more intuitive and clear. And as the native twitter app uses it I think its fair to say it is a UI concept a large amount of people are familiar with.
G
Guille Polito

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 :)


J
Jossy Paul

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

Works with:

ListView
ExpandableListView
GridView
WebView
ScrollView
HorizontalScrollView
ViewPager

H
Hasan Raza

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.


g
goRGon

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 ;)


Plus one just for mentioning canChildScrollUp(). Very important!
e
edbaev

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" />


A
Asad Ali Choudhry

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);
            }
        });
    }

A
Ahsan Malik

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