Как я могу создать список, когда, когда вы достигнете конца списка, я получу уведомление, чтобы я мог загрузить больше элементов?
Как я могу создать список, когда, когда вы достигнете конца списка, я получу уведомление, чтобы я мог загрузить больше элементов?
Ответы:
Одним из решений является реализация 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).
firstVisible + visibleCount >= totalCountвыполняется несколько раз при нескольких вызовах слушателя. Если функция load-more является веб-запросом (скорее всего, так и будет), добавьте еще одну проверку, выполняется ли запрос или нет. С другой стороны, проверьте, не равен ли totalCount предыдущему общему количеству, потому что нам не нужно несколько запросов для одного и того же количества элементов в списке.
Просто хотел предложить решение, которое я использовал для своего приложения.
Он также основан на 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)если больше нет элементов или страниц.
ListFragmentтакже без проблем - просто следуйте каждому из шагов, описанных выше, и все будет в порядке;) Или вы могли бы предоставить какие-либо сообщения об ошибках?
getListView().setOnScrollListener(this)
Вы можете определить конец списка с помощью 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 )
getView. Например, вам не гарантировано, что posпросматривает пользователь. Это может быть просто измерение ListView.
В Ognyan Bankov GitHubя нашел простое и работающее решение!
Это делает использование Volley HTTP libraryсетей Android-приложений проще, а главное, быстрее. Залп доступен через открытый репозиторий AOSP.
Данный код демонстрирует:
Для будущей консистенции я раздвоил репо Банкова .
Вот решение, которое также упрощает отображение представления загрузки в конце 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#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");
}
});
Это событие срабатывает один раз, когда нижний колонтитул становится видимым и работает как шарм.
Ключ этой проблемы - обнаружить событие load-more, запустить асинхронный запрос данных и затем обновить список. Также необходим адаптер с индикатором загрузки и другими декораторами. На самом деле, проблема очень сложна в некоторых угловых случаях. Просто OnScrollListenerреализации недостаточно, потому что иногда элементы не заполняют экран.
Я написал персональный пакет, который поддерживает бесконечный список RecyclerView, а также предоставляет реализацию асинхронного загрузчика, AutoPagerFragmentкоторая позволяет очень легко получать данные из многостраничного источника. Он может загрузить любую страницу в RecyclerViewпользовательское событие, а не только следующую страницу.
Вот адрес: https://github.com/SphiaTower/AutoPagerRecyclerManager
Лучшее решение, которое я когда-либо видел, - это библиотека 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) {
}
});
Я знаю, что это старый вопрос, и мир 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 возвращает вызов метода суперкласса 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-файле и поместите ее, как показано в коде адаптера выше.
Наслаждаться.