Cómo implementar Android Pull-to-Refresh

433

En aplicaciones de Android como Twitter (aplicación oficial), cuando encuentre un ListView, puede desplegarlo (y se recuperará cuando se lance) para actualizar el contenido.

Me pregunto cuál es la mejor manera, en su opinión, de implementar eso.

Algunas posibilidades que se me ocurren:

  1. Un elemento en la parte superior de ListView; sin embargo, no creo que volver a la posición 1 del elemento (basado en 0) con animación en ListView sea una tarea fácil.
  2. Otra vista fuera de ListView, pero tengo que ocuparme de mover la posición de ListView hacia abajo cuando se tira, y no estoy seguro de si podemos detectar si los toques de arrastre a ListView todavía realmente desplazan los elementos en ListView.

¿Alguna recomendación?

PD: Me pregunto cuándo se lanzará el código fuente oficial de la aplicación de Twitter. Se ha mencionado que se lanzará, pero han pasado 6 meses y no hemos tenido noticias suyas desde entonces.

Randy Sugianto 'Yuku'
fuente
Es esta funcionalidad se puede implementar en un TableLayout creado dinámicamente. Por favor, ayuda .....
Arun Badole
github.com/fruitranger/PulltorefreshListView es otra implementación mía. Soporte suave y multitáctil.
Changwei Yao
66
Relacionado: "Pull-to-refresh": un patrón anti UI en Android es un artículo que argumenta que esta IU no es algo que deba usarse en Android y provocó mucha discusión sobre su idoneidad.
blahdiblah
29
Alguien debería avisar a Google porque la última versión de Gmail para Android usa este "anti patrón".
Nick
44
Tirar para actualizar es (y ha sido durante un tiempo) un patrón estándar adoptado en iOS y Android y es muy natural, por lo que esta discusión antipatrón está desactualizada. Los usuarios esperarán verlo y comportarse como tal.
Martin Marconcini

Respuestas:

311

¡Finalmente, Google lanzó una versión oficial de la biblioteca pull-to-refresh!

Se llama SwipeRefreshLayout, dentro de la biblioteca de soporte, y la documentación está aquí :

  1. Agregue SwipeRefreshLayoutcomo vista principal, que se tratará como una extracción para actualizar el diseño. (Tomé ListViewcomo ejemplo, puede ser Viewcomo LinearLayout, ScrollViewetc.)

    <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. Agrega un oyente a tu clase

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

También puede llamar pullToRefresh.setRefreshing(true/false);según sus requisitos.

ACTUALIZAR

Las bibliotecas de soporte de Android han quedado en desuso y han sido reemplazadas por AndroidX. El enlace a la nueva biblioteca se puede encontrar aquí .

Además, debe agregar la siguiente dependencia a su proyecto:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'

O

Puede ir a Refactor >> Migrar a AndroidX y Android Studio se encargará de las dependencias por usted.

Randy Sugianto 'Yuku'
fuente
3
¿Puedo usar una barra de progreso en lugar de una combinación de colores en SwipeRefreshLayout?
pablobaldez
54
1 de abril de 2014 - y eso no fue una broma
aeracode
2
Código de ejemplo guías.codepath.com
david72
80

Intenté implementar un componente de extracción para actualizar, está lejos de estar completo pero demuestra una posible implementación, https://github.com/johannilsson/android-pulltorefresh .

La lógica principal se implementa en PullToRefreshListViewese sentido ListView. Internamente controla el desplazamiento de una vista de encabezado usando smoothScrollBy(API Nivel 8). El widget ahora se actualiza con soporte para 1.5 y posterior, por favor lea el archivo README para soporte 1.5.

En sus diseños simplemente lo agrega así.

<com.markupartist.android.widget.PullToRefreshListView
    android:id="@+id/android:list"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />
Johan Berg Nilsson
fuente
3
Hola johan, he descargado tu código de muestra. Funciona en el dispositivo Android 2.2 pero no funciona en el dispositivo 2.1. Creo que porque utiliza el método smoothScrollBy que solo está disponible en 2.2 o posterior, ¿es correcto? ¿Y tiene alguna idea para implementar este efecto en 2.1 o una versión anterior? Gracias
Sí, eso es correcto, como dije en la respuesta que smoothScrollBy introdujo en el API Nivel 8 (2.2). Todavía no he descubierto una forma adecuada de implementarlo para otras versiones, pero supongo que debería ser posible portar la implementación de smoothScrollBy, pero supongo que la discusión debe mantenerse en el sitio del proyecto y no en el desbordamiento de pila.
Johan Berg Nilsson
¿Es a propósito que la identificación es @ + id / android: list y no @android: id / list, se ve raro? El proyecto arroja un error de inflación aquí de mi lado, actualmente estoy revisando eso ...
Mathias Conradt
12
Esta es la mejor biblioteca para extraer para actualizar que he encontrado .. github.com/chrisbanes/Android-PullToRefresh . Funciona con ListViews, GridViews y Webviews. También se ha implementado Pull up para actualizar el patrón.
rOrlig 01 de
1
¿Cómo agrego el proyecto a la carpeta de la biblioteca mientras trabajo en Intellij Idea? Alguien puede ayudarme?
Mustafa Güven
55

También he implementado una biblioteca PullToRefresh robusta, de código abierto, fácil de usar y altamente personalizable para Android. Puede reemplazar su ListView con PullToRefreshListView como se describe en la documentación en la página del proyecto.

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

Erik
fuente
Intenté todas las implementaciones enumeradas aquí y la suya es la mejor, en términos de una extracción simple / pura / suave para actualizar la implementación (sin tocar para actualizar rarezas como la de Johan). ¡Gracias!
Gady
1
¿Puede esto reemplazar un ListView estándar para trabajar con ListActivity, ListFragment, etc.?
davidcsb
Sí, solo déle a PullToRefreshListView la identificación correcta. En XML: android: id = "@ android: id / list"
Erik
1
¡Esto es absolutamente increíble! Google me trajo aquí, y mirando los ejemplos, el suyo es el más fácil de implementar. bravo y gracias señor!
Evan R.
Componente muy sensiblemente diseñado, agradable y simple. Esta definitivamente debería ser la respuesta aceptada.
Adam
42

La forma más fácil que creo es la proporcionada por la biblioteca de soporte de Android:

android.support.v4.widget.SwipeRefreshLayout;

una vez que se importa, puede tener su diseño definido de la siguiente manera:

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

Supongo que usa la vista de reciclador en lugar de la vista de lista. Sin embargo, listview todavía funciona, por lo que solo necesita reemplazar la vista de reciclaje con viewview y actualizar las referencias en el código de Java (Fragmento).

En su fragmento de actividad, primero implemente la interfaz 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);

   }
}

Espero que esto ayude a las masas

larrytech
fuente
Funciona bien. Sin embargo, una cosa con respecto a setRefreshing: "No llame a esto cuando la actualización se active por un gesto de deslizamiento" como se describe en developer.android.com/reference/android/support/v4/widget/…
gabriel14
¡Buen trabajo! Gracias.
technik
22

En este enlace, se puede encontrar un tenedor de la famosa PullToRefreshvista que tiene nuevas implementaciones interesantes como PullTorRefreshWebViewo PullToRefreshGridViewo la posibilidad de añadir una PullToRefreshen el borde inferior de una lista.

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

Y lo mejor de todo es que funciona perfectamente en Android 4.1 (lo normal PullToRefreshno funciona)

Aracem
fuente
3
Un gran comentario en la parte superior del archivo Léame indica: ESTE PROYECTO YA NO SE MANTENDRÁ MÁS. De todos modos, ¡esta lib es la mejor que he visto hasta ahora! ¡Buen trabajo!
Milton
3
El hecho de que ya no se mantenga, no significa que no sea bueno. Aún así utilizarlo para toda mi tracción a las necesidades de actualización :)
Muz
18

Tengo una manera muy fácil de hacer esto, pero ahora estoy seguro de que es la manera infalible. Hay mi código 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;
    }
}

Solo necesita implementar ListViewTouchEventListener en su actividad donde desea usar este ListView y configurar el oyente

Lo tengo implementado en 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");
    }
}

Esto funciona para mi :)

Pushpan
fuente
18

Para implementar Android Pull-to-Refresh, pruebe este código,

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

Clase de actividad:

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

 }
mani
fuente
1
Gracias, realmente me ayudó
Arpan Sharma
9

Nadie ha mencionado el nuevo tipo de "Tire para actualizar" que se muestra en la parte superior de la barra de acción como en la aplicación Google Now o Gmail.

Hay una biblioteca ActionBar-PullToRefresh que funciona exactamente igual.

tomrozb
fuente
7

Tenga en cuenta que hay problemas de UX con los que lidiar cuando se implementa en Android y WP.

"Un gran indicador de por qué los diseñadores / desarrolladores no deberían implementar pull-to-refresh en el estilo que hacen las aplicaciones de iOS es cómo Google y sus equipos nunca usan pull-to-refresh en Android mientras lo hacen en iOS".

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

uobroin
fuente
3
Sé que esto tiene más de un año, pero la aplicación Gmail usa pull-to-refresh. Sin embargo, no es exactamente lo mismo en términos de la interfaz de usuario, la lista no se desplaza hacia abajo, sino que se muestra una nueva vista en la parte superior de la pantalla.
ashishduh
4

Si no desea que su programa se vea como un programa de iPhone que se ajusta a la fuerza en Android, busque un aspecto más nativo y haga algo similar a Gingerbread:

texto alternativo

Lie Ryan
fuente
2
@Rob: Me refería a tener la sombra naranja en la parte superior de la lista cuando se sobrecarga, en lugar de que la lista se recupere como en el iPhone. Esto se entiende como un comentario (no una respuesta), pero los comentarios no pueden tener imágenes.
Mentira Ryan
Ahh, lo siento, gran idea. Todavía no he jugado con pan de jengibre, así que no había visto el efecto. Todavía estoy esperando que google lo pase al nexo.
Rob
99
Tengo Gingerbread y el brillo naranja funciona muy bien cuando una lista es estática. Pero la actualización desplegable es un gran mecanismo de interfaz de usuario para actualizar una lista dinámica. Aunque es frecuente en el mundo de iOS, es un truco de interfaz de usuario que no se siente extraño en el ecosistema de Android. Le sugiero que lo consulte en la aplicación oficial de Twitter. :)
Thierry-Dimitri Roy
El comportamiento nativo aquí es indicar que ha llegado al final de una lista. Tomar esto y realizar una actualización es idénticamente no nativo, ya que no está haciendo lo que hace la plataforma. Esto significa que es más probable que sorprenda al usuario. Ciertamente no esperaría ni querría una actualización solo porque llegué al final de una lista. Tire hacia abajo para actualizar es mucho más intuitivo y claro. Y como la aplicación nativa de Twitter la usa, creo que es justo decir que es un concepto de interfaz de usuario con el que una gran cantidad de personas está familiarizada.
steprobe
4

He escrito un componente de extracción para actualizar aquí: https://github.com/guillep/PullToRefresh Funciona si la lista no tiene elementos, y lo he probado en> = 1.6 teléfonos Android.

Cualquier sugerencia o mejora es apreciada :)

Guille Polito
fuente
1

Para obtener la última actualización Pull-To de Lollipop:

  1. Descargue la última biblioteca de soporte de Lollipop SDK y Extras / Android
  2. Establezca el objetivo de compilación del proyecto en Android 5.0 (de lo contrario, el paquete de soporte puede tener errores con los recursos)
  3. Actualice su libs / android-support-v4.jar a la versión 21
  4. Use android.support.v4.widget.SwipeRefreshLayoutplusandroid.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

Puede encontrar una guía detallada aquí: http://antonioleiva.com/swiperefreshlayout/

Además de ListView, recomiendo leer canChildScrollUp()en los comentarios;)

Gorgona
fuente
Más uno solo por mencionar canChildScrollUp (). ¡Muy importante!
Petro
1

Muy interesante Pull-to-Refresh de Yalantis . Gif para iOS, pero puedes consultarlo :)

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

edbaev
fuente
0

Primero debemos saber qué es Pull para actualizar el diseño en Android. podemos llamar a pull para actualizar en Android como deslizar para actualizar. cuando desliza la pantalla de arriba a abajo, realizará alguna acción basada en setOnRefreshListener.

Aquí hay un tutorial que demuestra cómo implementar Android pull para actualizar. Espero que esto ayude.

Hasan Raza
fuente