Як реалізувати Android Pull-to-Refresh


432

У таких додатках для Android, як Twitter (офіційний додаток), коли ви стикаєтесь з ListView, ви можете зняти його (і він відскочить назад, коли вийде), щоб оновити вміст.

Цікаво, який найкращий спосіб, на вашу думку, здійснити це?

Деякі можливості, про які я міг придумати:

  1. Елемент вгорі списку ListView - однак, я не думаю, що прокрутка назад до позиції елемента 1 (на основі 0) з анімацією на ListView - це легке завдання.
  2. Інший погляд поза ListView - але мені потрібно подбати про переміщення позиції ListView вниз, коли вона витягнута, і я не впевнений, чи зможемо ми виявити, чи перетягування до ListView все ще дійсно прокручує елементи на ListView.

Будь-які рекомендації?

PS Цікаво, коли буде випущено офіційний вихідний код програми Twitter. Згадувалося, що він буде випущений, але пройшло 6 місяців, і ми з тих пір не чули про нього.


Чи ця функціональність може бути реалізована в динамічно створеній таблиці. Будь ласка, допоможіть .....
— Arun Badole

github.com/fruitranger/PulltorefreshListView - це ще одна моя реалізація. Плавна та багатоконтактна підтримка.
— Changwei Yao

6
Пов’язане: “Повторне оновлення”: анти-інтерфейс інтерфейсу на Android - це стаття, що стверджує, що цей інтерфейс не є тим, що слід використовувати на Android, і викликало багато дискусій щодо його доцільності.
— blahdiblah

29
Хтось повинен повідомити Google, оскільки в останній версії Gmail для Android використовується цей "антидіапазон".
— Нік

4
Оновлення - це стандартний прийнятий зразок в iOS та Android, і це дуже природно, тому ця дискусія щодо анти-шаблону застаріла. Користувачі очікують, що це побачать і поводяться як такі.
— Мартін Марконніні

Відповіді:


310

Нарешті, Google випустила офіційну версію бібліотеки "оновлення для оновлення"!

Він називається SwipeRefreshLayoutвсередині бібліотеки підтримки, і документація знаходиться тут :

  1. Додайте SwipeRefreshLayoutяк батьківський погляд, який розглядатиметься як потяг, щоб оновити макет. (Я взявListView в якості прикладу, це може бути будь-який , Viewяк LinearLayout, і ScrollViewт.д.)

    <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. Додайте слухача до свого класу

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

Ви також можете зателефонувати pullToRefresh.setRefreshing(true/false);відповідно до вашої вимоги.

ОНОВЛЕННЯ

Бібліотеки підтримки Android застаріли і були замінені AndroidX. Посилання на нову бібліотеку можна знайти тут .

Крім того, вам потрібно додати до свого проекту таку залежність:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'

АБО

Ви можете перейти до Refactor >> Переміститись на AndroidX, і Android Studio буде обробляти залежності від вас.


3
чи можна використовувати ProgressBar замість кольорової схеми на SwipeRefreshLayout?
— pablobaldez

54
1 квітня '14 - і це не жарт
— аерокод


80

Я здійснив спробу впровадити компонент "тягнути до оновлення", він ще далеко не повний, але демонструє можливу реалізацію, https://github.com/johannilsson/android-pulltorefresh .

Основна логіка реалізована в PullToRefreshListViewтому, що розширюється ListView. Внутрішньо він управляє прокруткою подання заголовка за допомогою smoothScrollBy(API рівня 8). Тепер віджет оновлюється підтримкою для версії 1.5 і пізніше, будь ласка, прочитайте README для підтримки 1.5.

У своїх макетах ви просто додаєте його так.

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

3
Привіт Джохане, я завантажив твій зразок коду. Він працює в пристрої Android 2.2, але не працює в пристрої 2.1. Я думаю, тому що він використовував метод smoothScrollBy, який доступний лише у версії 2.2 або пізнішої? І чи маєте ви ідею реалізувати цей ефект у версії 2.1 чи більш ранній? Дякую

Так, це правильно, як я зазначив у відповіді smoothScrollBy вводиться в API рівня 8 (2.2). Я ще не з'ясував належного способу його реалізації для інших версій, але, мабуть, має бути можливим перенести реалізацію smoothScrollBy, але я думаю, що обговорення слід вести на сайті проекту, а не на переповненні стека?
— Йохан Берг Нільссон

Чи це задумано, що id @ + id / android: list, а не @android: id / list, виглядає дивно? Проект кидає тут помилку інфляції на моєму боці, я зараз перевіряю це ...
— Матіас Конрадт

12
Це найкраща бібліотека для оновлення, яку я знайшов .. github.com/chrisbanes/Android-PullToRefresh . Він працює з ListView, GridViews та Webviews. Також виконано функцію "Підтягнути", щоб оновити шаблон.
— rOrlig

1
Як додати проект у папку бібліотеки під час роботи над Intellij Idea? Хтось може мені допомогти?
— Мустафа Гювен

55

Я також реалізував надійну, відкриту програму, простий у користуванні та дуже настроювану бібліотеку PullToRefresh для Android. Ви можете замінити ListView на PullToRefreshListView, як описано в документації на сторінці проекту.

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


Я спробував усі перераховані тут реалізації, і ваша найкраща, з точки зору простого / чистого / плавного потягу, щоб оновити реалізацію (немає натискання, щоб оновити дивацтво, як у Йогана). Дякую!
— Гаді

1
Чи може це замінити стандартний ListView для роботи з ListActivity, ListFragment тощо?
— davidcesarino

Так, просто введіть правильний ідентифікатор PullToRefreshListView. У XML: android: id = "@ android: id / list"
— Ерік

1
це абсолютно дивовижно! google привів мене сюди, і переглядаючи приклади, ваш погляд виглядає найпростішим у виконанні. браво і дякую сер!
— Еван Р.

Дуже грамотно розроблений компонент, приємний і простий. Це безумовно має бути прийнятою відповіддю.
— Адам

42

Найпростіший спосіб, на який я думаю, - це передбачено бібліотекою підтримки Android:

android.support.v4.widget.SwipeRefreshLayout;

Після того, як це імпортовано, ви можете мати ваш макет визначений наступним чином:

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

Я припускаю, що ви використовуєте перегляд рециркулятора замість listview. Однак, перегляд списку все ще працює, тому вам просто потрібно замінити рециркулятор на перегляд списку та оновити посилання в коді Java (Фрагмент).

У фрагменті вашої діяльності ви спочатку реалізуєте інтерфейс 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);

   }
}

Сподіваюсь, це допомагає масам


Це добре працює. Хоча одне, що стосується setRefreshing: "Не називайте це, коли оновлення спрацьовує пальцем жестом", як описано в developer.android.com/reference/android/support/v4/widget/…
— gabriel14

Хороша робота! Дякую.
— технік

22

У цьому посиланні ви можете знайти вилку відомого PullToRefreshвиду, яка має нові цікаві реалізації, як-от PullTorRefreshWebViewабо, PullToRefreshGridViewабо можливість додати a PullToRefreshв нижньому краї списку.

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

І найкраще, що в Android 4.1 працює нормально (нормально PullToRefreshне працює)


3
Великий коментар у верхній частині прочитаного свідчить: ЦІЙ ПРОЕКТ НЕ БУДЕ ВІДПОВІДЖЕНО. У всякому разі, ця лійка - найкраща, яку я бачив досі! Чудова робота!
— Мілтон

3
Тільки тому, що його більше не підтримують, не означає, що це не добре. Все-таки використовуйте його для всіх моїх тягнути, щоб оновити потреби :)
— Муз

18

У мене дуже простий спосіб зробити це, але тепер впевнений, що його бездоганний спосіб. Є мій код 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;
    }
}

Вам просто потрібно впровадити ListViewTouchEventListener у своїй діяльності, де ви хочете використовувати цей ListView та встановити слухача

У мене це реалізовано в 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");
    }
}

Це працює для мене :)


18

Щоб реалізувати Android Pull-to-Refresh, спробуйте цей фрагмент коду,

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

Клас діяльності:

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 дуже допоміг мені
— Арпан Шарма

9

Ніхто не згадав про новий тип "Потягнути, щоб оновити", який відображається вгорі панелі дій, як у додатку Google Асистент чи Gmail.

Існує бібліотека ActionBar-PullToRefresh, яка працює точно так само.


7

Зауважте, є проблеми з UX, з якими можна вирішуватись під час впровадження на Android та WP.

"Чудовим показником того, чому дизайнери / розробники не повинні впроваджувати оновлення в стилі додатків для iOS, - це те, як Google та їх команди ніколи не використовують функцію" pull-to-refresh "на Android, поки вони використовують її в iOS."

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


3
Я знаю, що це вже більше року, але додаток Gmail використовує функцію "оновлення для оновлення". Однак це не зовсім те саме, що стосується інтерфейсу користувача, список не прокручується вниз, скоріше новий вид відображається у верхній частині екрана.
— ашишдух

4

Якщо ви не хочете, щоб ваша програма була схожа на програму iPhone, яка вбудована в Android, націліться на рідніший вигляд і зробіть щось подібне до Пряників:

alt текст


2
@Rob: Я мав на увазі мати помаранчеву тінь у верхній частині списку, коли ви переплачуєте, замість того, щоб список відскочив назад, як на iPhone. Це розуміється як коментар (не відповідь), але коментарі не можуть мати зображення.
— Лежати Райан

Ах, вибачте, чудова ідея. Я ще не грав з пряниками, тому не бачив ефекту. Ще чекаю, коли Google перекине його на Nexus.
— Роб

9
У мене пряник, і апельсинове сяйво чудово працює, коли список статичний. Але спадне оновлення - це великий механізм інтерфейсу користувача для оновлення динамічного списку. Хоча він є поширеним у світі iOS, це фокус інтерфейсу, який не відчуває себе в екосистемі Android. Я настійно пропоную вам перевірити це в офіційному додатку Twitter. :)
— Тьєррі-Димитрі Рой

Народна поведінка тут означає, що ви досягли кінця списку. Здійснюючи це, виконувати оновлення ідентично не є рідним, оскільки ви не робите те, що робить платформа. Це означає, що ви швидше здивуєте користувача. Я, звичайно, не сподівався і не хочу оновити лише тому, що я потрапив до кінця списку. Потягнути вниз, щоб оновити, набагато інтуїтивніше і зрозуміліше. І тому як його використовує нативний твіттер, я вважаю, що це справедливо сказати, що це концепція інтерфейсу, з якою знають велику кількість людей.
— степроб

4

Я написав тут, щоб оновити компонент: https://github.com/guillep/PullToRefresh Це працює подія, якщо в списку немає елементів, і я перевірив його на андроїд телефонів> = 1.6.

Будь-яка пропозиція чи покращення вдячні :)



1

Щоб отримати останню версію Lollipop Pull-To Refresh:

  1. Завантажте останню бібліотеку підтримки Lollipop SDK та додатки / Android
  2. Встановіть Project Build Target на Android 5.0 (інакше пакет підтримки може мати помилки з ресурсами)
  3. Оновіть свої файли libs / android-support-v4.jar до 21-ї версії
  4. Використовуйте android.support.v4.widget.SwipeRefreshLayoutплюсandroid.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

Детальний посібник можна знайти тут: http://antonioleiva.com/swiperefreshlayout/

Плюс до ListView я рекомендую прочитати про це canChildScrollUp()в коментарях;)


Плюс один лише для згадування canChildScrollUp (). Дуже важливо!
— Петро

1

Дуже цікавий " Повторне оновлення" від Yalantis . Gif для iOS, але ви можете це перевірити :)

<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

Спершу ми повинні знати, що таке "Потягнути", щоб оновити макет в Android. ми можемо викликати потягнути, щоб оновити в Android, як проведіть пальцем для оновлення. при проведенні пальцем по екрану зверху вниз він виконає певну дію на основі setOnRefreshListener.

Ось підручник, який демонструє, як реалізувати андроїд тягнути, щоб оновити. Я сподіваюся, що це допомагає.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.