Android Endless List

Как создать список, где, когда вы дойдете до конца списка, я получаю уведомление, чтобы загрузить больше товаров?

Ответ 1

Одним из решений является реализация 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).

Ответ 2

Просто хотел внести решение, которое я использовал для своего приложения.

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

  • Пусть ваш ListFragment или ListActivity реализует OnScrollListener
  • Добавьте следующие методы в этот класс:

    @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, например, пользователю нужно прокрутить список до конца, чтобы загрузить больше элементов.

  • (необязательно) Как вы можете видеть, "проверка нагрузки больше" вызывается только тогда, когда пользователь перестает прокручивать. Чтобы повысить удобство использования, вы можете раздуть и добавить индикатор загрузки в конец списка через 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>
    
  • (необязательно). Наконец, удалите этот индикатор загрузки, вызвав listView.removeFooterView(yourFooterView), если больше нет элементов или страниц.

Ответ 3

Вы можете обнаружить конец списка с помощью 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() внутри вашего адаптера, чтобы обновить представление (он должен запускаться в пользовательском интерфейсе thread - runOnUiThread)

Ответ 4

В Ognyan Bankov GitHub я нашел простое и эффективное решение!

В нем используется Volley HTTP library, что упрощает работу сети для приложений Android, а самое главное - быстрее. Волейбол доступен через открытый репозиторий AOSP.

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

  • ListView, который заполняется запрограммированными запросами HTTP.
  • Использование NetworkImageView.
  • "Бесконечный" список страниц ListView с функцией чтения вперед.

Для будущей консистенции я разветвлено Bankov repo.

Ответ 5

Вот решение, которое также облегчает отображение вида загрузки в конце 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. Вы можете использовать этот класс напрямую или от него.

Ответ 6

Может быть, немного поздно, но следующее решение оказалось очень полезным в моем случае. В некотором смысле все, что вам нужно сделать, это добавить в свой 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");
    }
});

Это событие срабатывает один раз, когда нижний колонтитул становится видимым и работает как шарм.

Ответ 7

Я работаю над другим решением, очень похожим на это, но я использую 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) {

    }
});

Ответ 8

Ключом этой проблемы является обнаружение события load-more, запуск асинхронного запроса данных, а затем обновление списка. Также необходим адаптер с индикатором загрузки и другими декораторами. На самом деле проблема в некоторых случаях имеет очень сложную задачу. Просто реализация OnScrollListener недостаточна, потому что иногда элементы не заполняют экран.

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

Вот адрес: https://github.com/SphiaTower/AutoPagerRecyclerManager

Ответ 9

Лучшее решение, которое я видел, находится в FastAdapter для просмотра ресайклеров. Он имеет EndlessRecyclerOnScrollListener.

Вот пример использования: EndlessScrollListActivity

Как только я использовал его для бесконечного списка прокрутки, я понял, что настройка очень надежная. Я определенно рекомендую его.

Ответ 10

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

Он использует BaseAdapter, используемый с ListView, чтобы определить, когда список был прокручен до последнего элемента или когда он прокручивается от последнего элемента.

Он поставляется с примером проекта (всего 100 строк кода Activity), который можно использовать, чтобы быстро понять, как он работает.

Простое использование:

class Boy{

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

}

Адаптер для хранения объектов Boy будет выглядеть так:


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 возвращает вызов метода getView суперкласса 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 и поместите ее, как показано в коде адаптера выше.

Наслаждаться.