Jak wdrożyć Android Pull-to-Refresh

432

W aplikacjach na Androida, takich jak Twitter (oficjalna aplikacja), gdy natrafisz na ListView, możesz go ściągnąć w dół (a on się odskoczy po zwolnieniu), aby odświeżyć zawartość.

Zastanawiam się, jaki jest Twoim zdaniem najlepszy sposób na wdrożenie tego?

Niektóre możliwości, o których mógłbym pomyśleć:

  1. Element nad ListView - jednak nie sądzę, że przewijanie z powrotem do pozycji 1 (oparte na 0) z animacją na ListView to łatwe zadanie.
  2. Kolejny widok poza ListView - ale muszę zadbać o przesunięcie pozycji ListView, gdy jest ona ciągnięta, i nie jestem pewien, czy możemy wykryć, czy przeciągnięcia do ListView nadal naprawdę przewijają elementy na ListView.

Jakieś rekomendacje?

PS Zastanawiam się, kiedy zostanie wydany oficjalny kod źródłowy aplikacji na Twitterze. Wspomniano, że zostanie wydany, ale minęło 6 miesięcy i od tego czasu o nim nie słyszeliśmy.

Randy Sugianto „Yuku”
źródło
Czy ta funkcjonalność może być zaimplementowana w dynamicznie tworzonym TableLayout. Proszę o pomoc .....
Arun Badole
github.com/fruitranger/PulltorefreshListView to kolejna moja realizacja. Płynna i wielodotykowa obsługa.
Changwei Yao,
6
Powiązane: „Pull-to-refresh”: wzór anty interfejsu użytkownika w Androidzie to artykuł, w którym argumentuje, że ten interfejs użytkownika nie powinien być używany w Androidzie i wywołał wiele dyskusji na temat jego stosowności.
blahdiblah
29
Ktoś powinien poinformować Google, ponieważ najnowsza wersja Gmaila na Androida używa tego „anty-wzoru”.
Nick
4
Funkcja „przeciągnij, aby odświeżyć” jest (i była przez jakiś czas) standardowym wzorcem przyjętym w iOS i Androidzie i jest bardzo naturalna, więc ta dyskusja na temat anty-wzorców jest nieaktualna. Użytkownicy będą oczekiwać, że go zobaczą i będą się tak zachowywać.
Martin Marconcini

Odpowiedzi:

310

Wreszcie Google wydało oficjalną wersję biblioteki pull-to-refresh!

Nazywa się on SwipeRefreshLayoutwewnątrz biblioteki wsparcia, a dokumentacja znajduje się tutaj :

  1. Dodaj SwipeRefreshLayoutjako element nadrzędny widoku, który będzie traktowany jako przeciągnięcie w celu odświeżenia układu. (Wziąłem ListViewjako przykład, może to być dowolny Viewjak LinearLayout, ScrollViewitd.)

    <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. Dodaj słuchacza do swojej klasy

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

Możesz również zadzwonić pullToRefresh.setRefreshing(true/false);zgodnie z wymaganiami.

AKTUALIZACJA

Biblioteki obsługi Androida zostały wycofane i zostały zastąpione przez AndroidX. Link do nowej biblioteki można znaleźć tutaj .

Ponadto należy dodać do projektu następującą zależność:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'

LUB

Możesz przejść do Refactor >> Migruj do AndroidX, a Android Studio zajmie się Twoimi zależnościami.

Randy Sugianto „Yuku”
źródło
3
czy mogę używać paska postępu zamiast schematu kolorów w SwipeRefreshLayout?
pablobaldez
54
1 kwietnia 14 ' - i to nie był żart
aeracode
80

Podjęłam próbę zaimplementowania komponentu pull to refresh, ale jeszcze nie jest ukończona, ale pokazuje możliwą implementację, https://github.com/johannilsson/android-pulltorefresh .

Główna logika jest zaimplementowana w PullToRefreshListViewtym rozszerzeniu ListView. Wewnętrznie kontroluje przewijanie widoku nagłówka za pomocą smoothScrollBy(API Level 8). Widżet został teraz zaktualizowany o obsługę wersji 1.5 i nowszych. Przeczytaj jednak plik README dotyczący obsługi wersji 1.5.

W swoich układach po prostu dodajesz go w ten sposób.

<com.markupartist.android.widget.PullToRefreshListView
    android:id="@+id/android:list"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />
Johan Berg Nilsson
źródło
3
Cześć John, pobrałem Twój przykładowy kod. Działa na urządzeniu z Androidem 2.2, ale nie działa na urządzeniu 2.1. Myślę, że ponieważ użył metody smoothScrollBy , która jest dostępna tylko w wersji 2.2 lub nowszej, jest poprawna? Czy masz pomysł na wdrożenie tego efektu w wersji 2.1 lub wcześniejszej? Dzięki
Tak, to prawda, jak powiedziałem w odpowiedzi smoothScrollBy został wprowadzony na poziomie API 8 (2.2). Nie wymyśliłem jeszcze właściwego sposobu implementacji go dla innych wersji, ale wydaje się, że powinna istnieć możliwość przeniesienia implementacji smoothScrollBy, ale myślę, że dyskusja powinna być prowadzona w witrynie projektu, a nie na przepełnieniu stosu?
Johan Berg Nilsson
Czy to celowo, że identyfikator to @ + id / android: list, a nie @android: id / list, wygląda dziwnie? Projekt rzuca tutaj na mnie błąd inflacji, obecnie sprawdzam, czy ...
Mathias Conradt
12
To najlepsza biblioteka do odświeżania, którą znalazłem. Github.com/chrisbanes/Android-PullToRefresh . Działa z ListViews, GridViews i Webviews. Zaimplementowano również funkcję Pull up, aby odświeżyć wzór.
rOrlig
1
Jak dodać projekt do folderu biblioteki podczas pracy nad Intellij Idea? Czy ktoś może mi pomóc?
Mustafa Güven
55

Zaimplementowałem również solidną, open source, łatwą w użyciu i wysoce konfigurowalną bibliotekę PullToRefresh dla Androida. Możesz zamienić ListView na PullToRefreshListView zgodnie z opisem w dokumentacji na stronie projektu.

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

Erik
źródło
Wypróbowałem wszystkie wymienione tutaj implementacje, a Twoja jest najlepsza, jeśli chodzi o proste / czyste / płynne przyciąganie do odświeżania implementacji (bez dotykania, aby odświeżyć dziwności, takie jak Johan). Dzięki!
Gady,
1
Czy to może zastąpić standardowy ListView do pracy z ListActivity, ListFragment i tak dalej?
davidcesarino
Tak, po prostu podaj właściwemu identyfikatorowi PullToRefreshListView. W XML: android: id = "@ android: id / list"
Erik
1
to jest absolutnie niesamowite! google sprowadziło mnie tutaj i przeglądając przykłady, twoje wygląda najłatwiejsze do wdrożenia. brawo i dziękuję panu!
Evan R.
Bardzo rozsądnie zaprojektowany element, ładny i prosty. To zdecydowanie powinna być zaakceptowana odpowiedź.
Adam
42

Myślę, że najłatwiejszy sposób zapewnia biblioteka obsługi Androida:

android.support.v4.widget.SwipeRefreshLayout;

po zaimportowaniu możesz zdefiniować układ w następujący sposób:

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

Zakładam, że używasz widoku programu do recyklingu zamiast widoku listy. Jednak widok listy nadal działa, więc wystarczy zastąpić widok recyklera widokiem listy i zaktualizować odwołania w kodzie Java (Fragment).

W swoim fragmencie aktywności najpierw implementujesz interfejs SwipeRefreshLayout.OnRefreshListener: tj

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

   }
}

Mam nadzieję, że to pomaga masom

Larrytech
źródło
To dobrze działa. Jednak jedna rzecz dotycząca setRefreshing: „Nie nazywaj tego, gdy odświeżanie jest wywoływane przez gest machnięcia”, jak opisano w developer.android.com/reference/android/support/v4/widget/…
gabriel14
Dobra robota! Dzięki.
technik
22

W tym łączu można znaleźć widelec słynnego PullToRefreshwidoku, który ma nowe interesujące implementacje, takie jak PullTorRefreshWebViewlub PullToRefreshGridViewlub możliwość dodania PullToRefreshdolnej krawędzi listy.

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

A najlepsze jest to, że działa idealnie w Androidzie 4.1 (normalne PullToRefreshnie działa)

Aracem
źródło
3
Duży komentarz w górnej części pliku Readme wskazuje: TEN PROJEKT NIE JEST JUŻ UTRZYMANY. W każdym razie ta lib jest najlepsza, jaką do tej pory widziałem! Świetna robota!
Milton
3
To, że nie jest już utrzymywane, nie znaczy, że nie jest dobre. Nadal używam tego do wszystkich moich potrzeb związanych z odświeżaniem :)
Muz
18

Mam bardzo łatwy sposób, aby to zrobić, ale teraz jestem pewien, że jest to niezawodny sposób. Istnieje mój kod 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;
    }
}

Musisz tylko zaimplementować ListViewTouchEventListener na swoim działaniu, w którym chcesz użyć tego ListView i ustawić detektor

Mam to zaimplementowane w 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");
    }
}

Mi to pasuje :)

Pushpan
źródło
18

Aby wdrożyć Android Pull-to-Refresh, wypróbuj ten fragment kodu,

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

Klasa aktywności:

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
źródło
1
Thanks.it naprawdę mi pomógł
Arpan Sharma
9

Nikt nie wspomniał o nowym typie „Przyciągnij, aby odświeżyć”, który wyświetla się nad paskiem akcji, jak w aplikacji Google Now lub Gmail.

Istnieje biblioteka ActionBar-PullToRefresh, która działa dokładnie tak samo.

tomrozb
źródło
7

Zauważ, że istnieją problemy z UX, z którymi należy się zmierzyć przy wdrażaniu na Androida i WP.

„Doskonałym wskaźnikiem tego, dlaczego projektanci / deweloperzy nie powinni stosować metody„ pull-to-refresh ”w stylu aplikacji na iOS, jest to, że Google i ich zespoły nigdy nie używają funkcji pull-to-odświeżanie na Androidzie, gdy używają go w iOS.

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

uobroin
źródło
3
Wiem, że ma to ponad rok, ale aplikacja Gmail korzysta z funkcji pull-to-refresh. Jednak nie jest to dokładnie to samo pod względem interfejsu użytkownika, lista nie przewija się w dół, a raczej nowy widok pokazuje się u góry ekranu.
ashishduh
4

Jeśli nie chcesz, aby Twój program wyglądał jak program iPhone'a, który jest na siłę dopasowywany do Androida, postaraj się uzyskać bardziej natywny wygląd i zrób coś podobnego do Piernika:

alternatywny tekst

Lie Ryan
źródło
2
@Rob: Miałem na myśli pomarańczowy cień na górze listy, gdy przepełniasz, zamiast odskakiwania listy jak na iPhonie. Jest to rozumiane jako komentarz (nie odpowiedź), ale komentarze nie mogą zawierać obrazów.
Lie Ryan,
Ach, przepraszam, świetny pomysł. Nie grałem jeszcze z piernikiem, więc nie widziałem efektu. Wciąż czekam, aż Google przetoczy go na Nexusa.
Rob
9
Mam Piernik, a pomarańczowy blask działa świetnie, gdy lista jest statyczna. Ale rozwijane odświeżanie jest doskonałym mechanizmem interfejsu użytkownika do odświeżania listy dynamicznej. Chociaż jest to powszechne w świecie iOS, jest to sztuczka interfejsu użytkownika, która nie wydaje się dziwna w ekosystemie Androida. Zdecydowanie zalecamy sprawdzenie tego w oficjalnej aplikacji na Twitterze. :)
Thierry-Dimitri Roy
Natywne zachowanie tutaj oznacza, że ​​osiągnąłeś koniec listy. Wykonanie tego i odświeżenie nie jest identyczne, ponieważ nie robisz tego, co robi platforma. Oznacza to, że z większym prawdopodobieństwem zaskoczysz użytkownika. Z pewnością nie spodziewałbym się ani nie chciałem odświeżenia tylko dlatego, że dotarłem do końca listy. Przeciągnij, aby odświeżyć, jest o wiele bardziej intuicyjny i przejrzysty. I ponieważ natywna aplikacja Twittera korzysta z niej, myślę, że uczciwie jest powiedzieć, że jest to koncepcja interfejsu użytkownika, którą zna wiele osób.
steprobe
4

Napisałem link do odświeżenia tutaj: https://github.com/guillep/PullToRefresh Działa, jeśli lista nie zawiera elementów, i przetestowałem go na telefonach z Androidem> = 1.6.

Wszelkie sugestie lub ulepszenia są mile widziane :)

Guille Polito
źródło
1

Aby uzyskać najnowszy Lollipop Pull-To Refresh:

  1. Pobierz najnowszy zestaw Lollipop SDK i bibliotekę pomocy dodatków / Androida
  2. Ustaw docelowy poziom budowania projektu na Android 5.0 (w przeciwnym razie pakiet pomocy może zawierać błędy w zasobach)
  3. Zaktualizuj swoją bibliotekę libs / android-support-v4.jar do wersji 21
  4. Użyj android.support.v4.widget.SwipeRefreshLayoutplusandroid.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

Szczegółowy przewodnik można znaleźć tutaj: http://antonioleiva.com/swiperefreshlayout/

Plus dla ListView Polecam przeczytać canChildScrollUp()w komentarzach;)

gorgona
źródło
Plus jeden za wzmiankę o canChildScrollUp (). Bardzo ważne!
Petro,
1

Bardzo ciekawe Pull-to-Refresh autorstwa Yalantis . Gif na iOS, ale możesz to sprawdzić :)

<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
źródło
0

Najpierw powinniśmy wiedzieć, co to jest Pull, aby odświeżyć układ w Androidzie. możemy wywołać pull, aby odświeżyć w Androidzie, przeciągając, aby odświeżyć. po przesunięciu ekranu od góry do dołu wykona on pewne działania w oparciu o setOnRefreshListener.

Oto samouczek, który pokazuje, jak zaimplementować ściąganie Androida w celu odświeżenia. Mam nadzieję, że to pomoże.

Hasan Raza
źródło