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.