Бесконечный список Android

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

9 ответов

Решение

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

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

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

Он также основан на 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) если нет больше предметов или страниц.

Вы можете определить конец списка с помощью 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)

В Ognyan Bankov GitHub я нашел простое и рабочее решение!

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

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

  1. ListView, который заполняется постраничными запросами HTTP.
  2. Использование NetworkImageView.
  3. "Бесконечная" нумерация страниц ListView с упреждающим чтением.

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

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

Может быть, немного поздно, но следующее решение оказалось очень полезным в моем случае. Таким образом, все, что вам нужно сделать, это добавить в свой ListView Footer и создать для этого addOnLayoutChangeListener,

http://developer.android.com/reference/android/widget/ListView.html

Например:

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

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

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

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

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

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

    }
});

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

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

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

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

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

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

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

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 возвращает вызов суперкласса 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);
                }
            }
        };

В loadMoreitem - это кнопка или другой элемент пользовательского интерфейса, по которому можно щелкнуть, чтобы получить дополнительные данные с URL-адреса. При размещении, как описано в коде, адаптер точно знает, когда показать эту кнопку, а когда отключить. Просто создайте кнопку в своем xml-файле и разместите ее, как показано в приведенном выше коде адаптера.

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

Другие вопросы по тегам