Android Endless List


232

Як я можу створити список, коли після досягнення кінця списку мене отримують сповіщення, щоб я міг завантажити більше елементів?


9
Я рекомендую EndWareAnd адаптер CommonWare: github.com/commonsguy/cwac-endless . Я знайшов це з цієї відповіді на інше запитання: stackoverflow.com/questions/4667064/… .
Тайлер Колліер

Мені потрібно ж thing..can будь-якої допомоги ..? Stackoverflow.com/questions/28122304 / ...

Відповіді:


269

Одним із варіантів є впровадження OnScrollListenerта внесення змін (наприклад, додавання елементів тощо) до ListAdapterзручного стану у своєму onScrollметоді.

Далі ListActivityпоказано список цілих чисел, починаючи з 40, додаючи елементи, коли користувач прокручує до кінця списку.

public class Test extends ListActivity implements OnScrollListener {

    Aleph0 adapter = new Aleph0();

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setListAdapter(adapter); 
        getListView().setOnScrollListener(this);
    }

    public void onScroll(AbsListView view,
        int firstVisible, int visibleCount, int totalCount) {

        boolean loadMore = /* maybe add a padding */
            firstVisible + visibleCount >= totalCount;

        if(loadMore) {
            adapter.count += visibleCount; // or any other amount
            adapter.notifyDataSetChanged();
        }
    }

    public void onScrollStateChanged(AbsListView v, int s) { }    

    class Aleph0 extends BaseAdapter {
        int count = 40; /* starting amount */

        public int getCount() { return count; }
        public Object getItem(int pos) { return pos; }
        public long getItemId(int pos) { return pos; }

        public View getView(int pos, View v, ViewGroup p) {
                TextView view = new TextView(Test.this);
                view.setText("entry " + pos);
                return view;
        }
    }
}

Очевидно, ви повинні використовувати окремі потоки для тривалих дій (наприклад, завантаження веб-даних) і, можливо, захочете вказати прогрес в останньому елементі списку (як це роблять ринок або gmail програми).


3
так, чи не призведе це до збільшення розміру адаптера, якби ви перестали прокручуватись посередині екрана? він повинен завантажувати наступні 10 лише тоді, коли фактично досягне нижнього списку.
Маттіас

9
Я помічаю дуже багато подібних прикладів за допомогою BaseAdapter. Хотілося зазначити, що якщо ви використовуєте базу даних, спробуйте скористатися SimpleCursorAdapter. Коли вам потрібно додати до списку, оновіть базу даних, отримайте новий курсор і скористайтеся SimpleCursorAdapter # changeCursor разом з notifyDataSetChanged. Не потрібно підкласифікація, і вона працює краще, ніж BaseAdapter (знову ж таки, лише якщо ви використовуєте базу даних).
браку

1
Після виклику notifyDataSetChanged () він перейде вгору списку, як я можу запобігти це?
нічия

2
Примітка. Я використовував цей підхід, але мені потрібно було додати чек на видимість, коли видимає значення 0. Для кожного списку я отримую один зворотний виклик на onScroll, де firstVisible, visibleCount і totalCount - це 0, що технічно відповідає умовному, але це не коли я хочу завантажувати більше.
Ерік Мілл

5
Ще одна проблема цього коду полягає в тому, що умова firstVisible + visibleCount >= totalCountвиконується кілька разів при багаторазових дзвінках до слухача. Якщо функцією для завантаження є веб-запит, (найімовірніше, це буде), додайте ще одну перевірку на те, чи запит продовжується чи ні. З іншого боку, перевірте, чи загальна кількість не дорівнює попередній загальній кількості, оскільки нам не потрібно багато запитів на одну і ту ж кількість елементів у списку.
Субін Себастьян

94

Просто хотів зробити свій внесок у рішення, яке я використав для свого додатка.

Він також базується на OnScrollListenerінтерфейсі, але я виявив, що він має значно кращі показники прокрутки на пристроях низького класу, оскільки жоден з обчислень видимого / загального підрахунку не проводиться під час операцій прокрутки.

  1. Дозвольте ListFragmentабо ListActivityреалізуйтеOnScrollListener
  2. Додайте наступні методи до цього класу:

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        //leave this empty
    }
    
    @Override
    public void onScrollStateChanged(AbsListView listView, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE) {
            if (listView.getLastVisiblePosition() >= listView.getCount() - 1 - threshold) {
                currentPage++;
                //load more list items:
                loadElements(currentPage);
            }
        }
    }

    де currentPageзнаходиться сторінка вашого джерела даних, яку слід додати до вашого списку, і thresholdчисельність елементів списку (рахується з кінця), яка, якщо вона буде видима, повинна запустити процес завантаження. Якщо ви встановите thresholdна 0, наприклад, користувач повинен прокрутити до самого кінця списку, щоб завантажити більше деталей.

  3. (необов’язково) Як бачите, "перевірка завантаження" викликається лише тоді, коли користувач перестає прокручувати. Щоб покращити зручність використання, ви можете надути і додати показник завантаження до кінця списку через listView.addFooterView(yourFooterView). Один з прикладів такого виду колонтитулів:

    <?xml version="1.0" encoding="utf-8"?>
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/footer_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp" >
    
        <ProgressBar
            android:id="@+id/progressBar1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_gravity="center_vertical" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/progressBar1"
            android:padding="5dp"
            android:text="@string/loading_text" />
    
    </RelativeLayout>
  4. (необов’язково) Видаліть цей показник завантаження, зателефонувавши, listView.removeFooterView(yourFooterView)якщо немає більше елементів або сторінок.


Я спробував це, але це не працює для ListFragment. Як це можна використовувати в ListFragment.
zeeshan

Що ж, я використовую його ListFragmentтакож без проблем - просто виконайте кожен із наведених вище кроків, і ви будете добре;) Або ви могли б надати будь-які повідомлення про помилки?
saschoar

Те , що ви , можливо, пропустили пояснюється в цьому SO відповідь: stackoverflow.com/a/6357957/1478093 -getListView().setOnScrollListener(this)
TBieniek

7
Примітка: додавання та видалення нижнього колонтитулу в списку перегляду проблематично (колонтитул не відображається, якщо setAdapter викликається перед додаванням нижнього колонтитулу), я змінив видимість подання нижнього колонтитула безпосередньо, не видаляючи його.
DVD

Що потрібно додати у loadElements (currentPage) ??? Я маю на увазі, чи називаю я AsyncTask чи потоком?
android_developer

20

Ви можете визначити кінець списку за допомогою onScrollListener , робочий код представлений нижче:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (view.getAdapter() != null && ((firstVisibleItem + visibleItemCount) >= totalItemCount) && totalItemCount != mPrevTotalItemCount) {
        Log.v(TAG, "onListEnd, extending list");
        mPrevTotalItemCount = totalItemCount;
        mAdapter.addMoreData();
    }
}

Ще один спосіб зробити це (у внутрішньому адаптері):

    public View getView(int pos, View v, ViewGroup p) {
            if(pos==getCount()-1){
                addMoreData(); //should be asynctask or thread
            }
            return view;
    }

Майте на увазі, що цей метод буде викликаний багато разів, тому вам потрібно додати ще одну умову, щоб заблокувати декілька викликів addMoreData().

Коли ви додаєте всі елементи до списку, зателефонуйте notifyDataSetChanged () всередині вашого адаптера, щоб оновити Перегляд (він повинен працювати на потоці інтерфейсу - runOnUiThread )


7
Дуже погано застосовувати інші речі, ніж повернути вигляд у getView. Наприклад, ви не гарантуєте, що користувач posперегляне. Це може бути просто вимірювальний матеріал ListView.
Томас Ейл

Я хочу завантажити більше предметів після прокрутки 10 елементів. але я помічаю, що завантаження починається до того, як 10-й елемент буде видно означає 9-й елемент. Тож як це зупинити?
Atul Bhardwaj

4

В Ognyan Bankov GitHubя знайшов просте і працююче рішення!

Це використовує те, Volley HTTP libraryщо робить мережу для додатків Android простішою, а головне, швидшою. Залп доступний через відкритий сховище AOSP.

Даний код демонструє:

  1. ListView, який заповнений HTTP-сторінками.
  2. Використання NetworkImageView.
  3. "Нескінченний" список сторінок ListView з попереднім читанням.

За подальшу послідовність я відправив репо на Банкові .


2

Ось рішення, яке також полегшує показ подання завантаження в кінці ListView під час його завантаження.

Ви можете подивитися класи тут:

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java - Помічник, щоб зробити його можливим використовувати. функції, не поширюючись на SimpleListViewWithLoadingIndicator.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - слухач, який починає завантажувати дані, коли користувач ось-ось досягне нижньої частини ListView.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - The EndlessListView. Ви можете використовувати цей клас безпосередньо або продовжити з нього.


1

Можливо, трохи пізно, але наступне рішення сталося дуже корисним у моєму випадку. Таким чином, все, що вам потрібно зробити, - це додати до свого ListView a Footerта створити для нього addOnLayoutChangeListener.

http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)

Наприклад:

ListView listView1 = (ListView) v.findViewById(R.id.dialogsList); // Your listView
View loadMoreView = getActivity().getLayoutInflater().inflate(R.layout.list_load_more, null); // Getting your layout of FooterView, which will always be at the bottom of your listview. E.g. you may place on it the ProgressBar or leave it empty-layout.
listView1.addFooterView(loadMoreView); // Adding your View to your listview 

...

loadMoreView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
         Log.d("Hey!", "Your list has reached bottom");
    }
});

Ця подія запускається один раз, коли колонтитул стає видимим і працює як шарм.


0

Ключ цієї проблеми полягає у виявленні події, що завантажує більше, запустіть запит на асинхронізацію даних, а потім оновіть список. Також потрібен адаптер з індикатором завантаження та іншими декораторами. Насправді проблема дуже складна в деяких кутових випадках. Просто OnScrollListenerвпровадження недостатньо, тому що іноді елементи не заповнюють екран.

Я написав особистий пакет, який підтримує нескінченний список RecyclerView, а також забезпечують реалізацію завантажувача асинхронізації, AutoPagerFragmentщо дуже легко отримує дані з багатосторінкового джерела. Він може завантажити будь-яку сторінку, яку ви хочете, RecyclerViewна спеціальну подію, а не лише на наступну.

Ось адреса: https://github.com/SphiaTower/AutoPagerRecyclerManager


Посилання розірвано.
DSlomer64

0

Найкраще рішення, яке я бачив, - це бібліотека FastAdapter для перегляду рециркуляторів. Він має EndlessRecyclerOnScrollListener.

Ось приклад використання: EndlessScrollListActivity

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


0

Я працюю над іншим рішенням, дуже подібним до цього, але я використовую a, footerViewщоб надати користувачеві можливість завантажувати більше елементів, натискаючи на кнопку footerView, я використовую "меню", яке показане над ListViewі внизу батьківського подання, це "меню" приховує нижню частину ListView, тому, коли listViewпрокрутка меню зникає, а коли стан прокрутки не працює, меню знову з'являється, але коли користувач прокручує до кінця listView, я "прошу" знайте, якщо footerViewв такому випадку показано значення "", меню не відображається, і користувач може побачити, footerViewщоб завантажити більше вмісту. Ось код:

З повагою

listView.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub
        if(scrollState == SCROLL_STATE_IDLE) {
            if(footerView.isShown()) {
                bottomView.setVisibility(LinearLayout.INVISIBLE);
            } else {
                bottomView.setVisibility(LinearLayout.VISIBLE);
            } else {
                bottomView.setVisibility(LinearLayout.INVISIBLE);
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {

    }
});

0

Я знаю, що це старе питання, і світ Android в основному перейшов до RecyclerViews, але для всіх, хто цікавиться, ця бібліотека може бути дуже цікавою.

Він використовує BaseAdapter, який використовується у ListView, щоб виявити, коли список прокручується до останнього елемента або коли він прокручується подалі від останнього елемента.

Він поставляється з прикладом проекту (ледь 100 рядків коду діяльності), який можна використовувати, щоб швидко зрозуміти, як він працює.

Просте використання:

class Boy{

private String name;
private double height;
private int age;
//Other code

}

Адаптер для зберігання хлопчикових предметів виглядатиме так:


public class BoysAdapter extends EndlessAdapter<Boy>{




        ViewHolder holder = null;


        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent
                    .getContext());

            holder = new ViewHolder();

            convertView = inflater.inflate(
                    R.layout.list_cell, parent, false);


            holder.nameView = convertView.findViewById(R.id.cell);

            // minimize the default image.
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        Boy boy = getItem(position);

        try {
            holder.nameView.setText(boy.getName());

            ///Other data rendering codes.

        } catch (Exception e) {
            e.printStackTrace();
        }

        return super.getView(position,convertView,parent);

}

Зверніть увагу, як метод getView BoysAdapter повертає виклик методу суперкласу EndlessAdapter getView. Це на 100% важливо.

Тепер, щоб створити адаптер, виконайте:

   adapter = new ModelAdapter() {
            @Override
            public void onScrollToBottom(int bottomIndex, boolean moreItemsCouldBeAvailable) {

                if (moreItemsCouldBeAvailable) { 
                    makeYourServerCallForMoreItems();
                } else {
                    if (loadMore.getVisibility() != View.VISIBLE) {
                        loadMore.setVisibility(View.VISIBLE);
                    }
                }
            }

            @Override
            public void onScrollAwayFromBottom(int currentIndex) { 
                loadMore.setVisibility(View.GONE);
            }

            @Override
            public void onFinishedLoading(boolean moreItemsReceived) { 
                if (!moreItemsReceived) {
                    loadMore.setVisibility(View.VISIBLE);
                }
            }
        };

loadMoreЕлемент використовується той чи інший елемент інтерфейсу , який може бути натиснуто , щоб витягти більше даних з URL. Розміщуючи так, як описано в коді, адаптер точно знає, коли показати цю кнопку та коли її відключити. Просто створіть кнопку у своєму xml та поставте її, як показано в коді адаптера вище.

Насолоджуйтесь.

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