Бесконечный список 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
интерфейс, но я обнаружил, что он имеет гораздо лучшую производительность прокрутки на младших устройствах, так как во время операций прокрутки не выполняется никаких расчетов видимого / общего количества.
- Пусть ваш
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)
если нет больше предметов или страниц.
Вы можете определить конец списка с помощью 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.
Данный код демонстрирует:
- ListView, который заполняется постраничными запросами HTTP.
- Использование NetworkImageView.
- "Бесконечная" нумерация страниц 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);
}
}
};
В loadMore
item - это кнопка или другой элемент пользовательского интерфейса, по которому можно щелкнуть, чтобы получить дополнительные данные с URL-адреса. При размещении, как описано в коде, адаптер точно знает, когда показать эту кнопку, а когда отключить. Просто создайте кнопку в своем xml-файле и разместите ее, как показано в приведенном выше коде адаптера.
Наслаждаться.