Como implementar o Android Pull-to-Refresh


433

Em aplicativos Android como o Twitter (aplicativo oficial), quando você encontra um ListView, pode puxá-lo para baixo (e ele se recupera quando lançado) para atualizar o conteúdo.

Gostaria de saber qual é a melhor maneira, na sua opinião, de implementar isso?

Algumas possibilidades que eu poderia pensar:

  1. Um item no topo do ListView - no entanto, não acho que rolar para a posição 1 do item (com base em 0) com animação no ListView é uma tarefa fácil.
  2. Outra exibição fora do ListView - mas preciso cuidar para mover a posição do ListView para baixo quando ela é puxada, e não tenho certeza se podemos detectar se os toques de arrastar para o ListView ainda rolam realmente os itens no ListView.

Alguma recomendação?

PS Gostaria de saber quando o código fonte oficial do aplicativo do Twitter é lançado. Foi mencionado que será lançado, mas já se passaram 6 meses e não ouvimos falar disso desde então.


Essa funcionalidade pode ser implementada em um TableLayout criado dinamicamente. Por favor ajude .....
— Arun Badole

O github.com/fruitranger/PulltorefreshListView é outra implementação minha. Suporte suave e multi-touch.
— Changwei Yao 16/07/12

6
Relacionado: "Puxar para atualizar": um padrão anti-UI no Android é um artigo que argumenta que essa interface não é algo que deve ser usado no Android e provocou muita discussão sobre sua adequação.
— blahdiblah

29
Alguém deve informar o Google, porque a versão mais recente do Gmail para Android usa esse "antipadrão".
— Nick

4
O Pull to refresh é (e já faz um tempo) um padrão adotado padrão no iOS e no Android e é muito natural; portanto, essa discussão antipadrão está desatualizada. Os usuários esperam vê-lo e se comportar como tal.
— Martin Marconcini 28/02

Respostas:


311

Finalmente, o Google lançou uma versão oficial da biblioteca pull-to-refresh!

É chamado SwipeRefreshLayout, dentro da biblioteca de suporte, e a documentação está aqui :

  1. Adicione SwipeRefreshLayoutcomo pai da vista, que será tratado como uma atração para atualizar o layout. (Tomei ListViewcomo exemplo, ele pode ser qualquer 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. Adicione um ouvinte à sua turma

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

Você também pode ligar pullToRefresh.setRefreshing(true/false);conforme sua exigência.

ATUALIZAR

As bibliotecas de suporte do Android foram descontinuadas e substituídas pelo AndroidX. O link para a nova biblioteca pode ser encontrado aqui .

Além disso, você precisa adicionar a seguinte dependência ao seu projeto:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'

OU

Você pode ir para Refatorar >> Migrar para AndroidX e o Android Studio manipulará as dependências para você.


3
posso usar uma ProgressBar em vez de Color Scheme no SwipeRefreshLayout?
— Pablobaldez

54
— 01/04


80

Fiz uma tentativa de implementar um componente pull to refresh, está longe de ser completo, mas demonstra uma possível implementação, https://github.com/johannilsson/android-pulltorefresh .

A lógica principal é implementada nesse PullToRefreshListViewsentido ListView. Internamente, ele controla a rolagem de uma visualização de cabeçalho usando smoothScrollBy(Nível 8 da API). O widget agora está atualizado com suporte para 1.5 e posterior, por favor leia o README para suporte a 1.5.

Nos seus layouts, você simplesmente o adiciona assim.

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

3
Oi johan, eu baixei o seu código de exemplo. Ele funciona no dispositivo Android 2.2, mas não no dispositivo 2.1. Eu acho que porque ele usou o método smoothScrollBy que só está disponível no 2.2 ou posterior, está correto? E você tem alguma ideia de implementar esse efeito na versão 2.1 ou anterior? Graças

Sim, isso está correto, como afirmei na resposta que smoothScrollBy foi introduzido na API Nível 8 (2.2). Ainda não descobri uma maneira adequada de implementá-lo para outras versões, mas acho que deve ser possível portar a implementação do smoothScrollBy, mas acho que a discussão deve ser mantida no site do projeto e não no excesso de pilha?
— Johan Berg Nilsson

É de propósito que o id é @ + id / android: list e não @android: id / list, parece estranho? O projeto gera um erro inflação aqui do meu lado, eu atualmente estou verificando em que ...
— Mathias Conradt

12
Esta é a melhor biblioteca para puxar para atualizar que encontrei .. github.com/chrisbanes/Android-PullToRefresh . Ele funciona com ListViews, GridViews e Webviews. Também possui Pull up para atualizar o padrão implementado.
— precisa saber é o seguinte

1
Como adiciono o projeto à pasta da biblioteca enquanto trabalho no Intellij Idea? Alguém pode me ajudar?
— Mustafa Güven

55

Também implementei uma biblioteca PullToRefresh robusta, de código aberto, fácil de usar e altamente personalizável para Android. Você pode substituir seu ListView pelo PullToRefreshListView, conforme descrito na documentação na página do projeto.

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


Eu tentei todas as implementações listadas aqui e a sua é a melhor, em termos de uma atração simples / pura / suave para atualizar a implementação (sem toque para atualizar a estranheza como a de Johan). Obrigado!
— Gady

1
Isso pode substituir um ListView padrão para funcionar com ListActivity, ListFragment e assim por diante?
— Davidcsb

Sim, apenas dê ao PullToRefreshListView a identificação correta. Em XML: android: id = "@ android: id / list"
— Erik

1
isso é absolutamente incrível! o google me trouxe aqui e, olhando os exemplos, o seu parece ser o mais fácil de implementar. bravo e obrigado senhor!
— Evan R.

Componente muito sensato, agradável e simples. Definitivamente, essa deve ser a resposta aceita.
— Adam

42

A maneira mais fácil que eu acho que é fornecida pela biblioteca de suporte do Android:

android.support.v4.widget.SwipeRefreshLayout;

depois de importado, você poderá definir seu layout da seguinte maneira:

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

Presumo que você use a exibição do reciclador em vez da exibição de lista. No entanto, o listview ainda funciona, então você só precisa substituir a recyclerview pelo listview e atualizar as referências no código java (fragmento).

No fragmento de atividade, você primeiro implementa a 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);

   }
}

Espero que isso ajude as massas


Isso funciona bem. Porém, uma coisa a respeito setRefreshing: "Não chame isso quando atualização é acionado por um gesto swipe", conforme descrito no developer.android.com/reference/android/support/v4/widget/...
— gabriel14

Bom trabalho! Obrigado.
— 22720 Technic,

22

Nesse link, você encontra uma bifurcação da famosa PullToRefreshexibição que possui novas implementações interessantes como PullTorRefreshWebViewou PullToRefreshGridViewou a possibilidade de adicionar uma PullToRefreshna borda inferior de uma lista.

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

E o melhor é que funciona perfeitamente no Android 4.1 (o normal PullToRefreshnão funciona)


3
Um grande comentário na parte superior do leia-me indica: ESTE PROJETO NÃO ESTÁ MAIS MANTIDO. Enfim, esta biblioteca é a melhor que eu já vi até agora! Ótimo trabalho!
— Milton

3
Só porque não está mais sendo mantido, não significa que não seja bom. Ainda usá-lo para toda a minha força para as necessidades de atualização :)
— Muz

18

Eu tenho uma maneira muito fácil de fazer isso, mas agora com certeza é a maneira infalível Existe o meu 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;
    }
}

Você só precisa implementar o ListViewTouchEventListener em sua atividade em que deseja usar esse ListView e definir o ouvinte

Eu o implementei em 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");
    }
}

Funciona para mim :)


18

Para implementar o Pull-to-Refresh do Android, tente 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>

Classe de atividade:

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

 }

1
Thanks.it realmente me ajudou
— Arpan Sharma

9

Ninguém mencionou o novo tipo de "Puxar para atualizar", exibido na parte superior da barra de ação, como no aplicativo Google Now ou Gmail.

Existe uma biblioteca ActionBar-PullToRefresh que funciona exatamente da mesma maneira.


7

Observe que há problemas de UX com os quais lidar ao implementar no Android e no WP.

"Um ótimo indicador de por que os designers / desenvolvedores não devem implementar o pull-to-refresh no estilo que os aplicativos iOS fazem é como o Google e suas equipes nunca usam o pull-to-refresh no Android enquanto o usam no iOS".

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


3
Eu sei que isso tem mais de um ano, mas o aplicativo Gmail usa o recurso de puxar para atualizar. No entanto, não é exatamente o mesmo em termos de interface do usuário, a lista não rola para baixo; uma nova exibição é exibida na parte superior da tela.
— ashishduh

4

Se você não deseja que seu programa se pareça com um programa do iPhone que se encaixa com força no Android, procure uma aparência mais nativa e faça algo semelhante ao Gingerbread:

texto alternativo


2
@ Rob: eu quis dizer ter a sombra laranja no topo da lista quando você exagerar, em vez de ter a lista retornando como no iPhone. Isso significa um comentário (não resposta), mas os comentários não podem ter imagens.
— Lie Ryan

Ah, desculpe, ótima idéia. Ainda não brinquei com pão de gengibre, então não tinha visto o efeito. Ainda estou esperando o google rolar para o nexus.
— Rob

9
Eu tenho pão de gengibre e o brilho laranja funciona muito bem quando uma lista é estática. Mas a atualização suspensa é um ótimo mecanismo de interface do usuário para atualizar uma lista dinâmica. Embora seja predominante no mundo iOS, é um truque de interface do usuário que não parece estranho no ecossistema Android. Eu sugiro fortemente que você dê uma olhada no aplicativo oficial do Twitter. :)
— Thierry-Dimitri Roy

O comportamento nativo aqui é indicar que você chegou ao final de uma lista. Tomar isso e executar uma atualização não são identicamente nativos, pois você não está fazendo o que a plataforma faz. Isso significa que você tem mais chances de surpreender o usuário. Eu certamente não esperaria nem desejaria uma atualização só porque cheguei ao final de uma lista. Puxe para baixo para atualizar é muito mais intuitivo e claro. E como o aplicativo nativo do twitter o usa, acho justo dizer que é um conceito de interface do usuário com o qual muitas pessoas estão familiarizadas.
— steprobe



1

Para obter a atualização mais recente do Lollipop Pull-To:

  1. Baixe a biblioteca de suporte mais recente do Lollipop SDK e Extras / Android
  2. Defina o destino da compilação do projeto como Android 5.0 (caso contrário, o pacote de suporte pode ter erros nos recursos)
  3. Atualize sua libs / android-support-v4.jar para a versão 21
  4. Use android.support.v4.widget.SwipeRefreshLayoutmaisandroid.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

Guia detalhado pode ser encontrado aqui: http://antonioleiva.com/swiperefreshlayout/

Além disso, para o ListView, eu recomendo ler canChildScrollUp()nos comentários;)


Mais um apenas por mencionar canChildScrollUp (). Muito importante!
— Petro

1

Pull-to-Refresh muito interessante da Yalantis . Gif para iOS, mas você pode conferir :)

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


0

Primeiro, devemos saber o que é o Pull para atualizar o layout no Android. podemos chamar pull para atualizar no Android como deslizar para atualizar. quando você desliza a tela de cima para baixo, ela executa alguma ação com base em setOnRefreshListener.

Aqui está o tutorial que demonstra como implementar o pull Android para atualizar. Eu espero que isso ajude.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.