Як реалізувати 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.