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