Як я можу створити список, коли після досягнення кінця списку мене отримують сповіщення, щоб я міг завантажити більше елементів?
Як я можу створити список, коли після досягнення кінця списку мене отримують сповіщення, щоб я міг завантажити більше елементів?
Відповіді:
Одним із варіантів є впровадження 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 програми).
firstVisible + visibleCount >= 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 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");
}
});
Ця подія запускається один раз, коли колонтитул стає видимим і працює як шарм.
Ключ цієї проблеми полягає у виявленні події, що завантажує більше, запустіть запит на асинхронізацію даних, а потім оновіть список. Також потрібен адаптер з індикатором завантаження та іншими декораторами. Насправді проблема дуже складна в деяких кутових випадках. Просто OnScrollListenerвпровадження недостатньо, тому що іноді елементи не заповнюють екран.
Я написав особистий пакет, який підтримує нескінченний список RecyclerView, а також забезпечують реалізацію завантажувача асинхронізації, AutoPagerFragmentщо дуже легко отримує дані з багатосторінкового джерела. Він може завантажити будь-яку сторінку, яку ви хочете, RecyclerViewна спеціальну подію, а не лише на наступну.
Ось адреса: https://github.com/SphiaTower/AutoPagerRecyclerManager
Найкраще рішення, яке я бачив, - це бібліотека FastAdapter для перегляду рециркуляторів. Він має EndlessRecyclerOnScrollListener.
Ось приклад використання: EndlessScrollListActivity
Після того, як я використав його для нескінченного прокручування списку, я зрозумів, що налаштування дуже надійне. Я б точно рекомендував це.
Я працюю над іншим рішенням, дуже подібним до цього, але я використовую a, 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 рядків коду діяльності), який можна використовувати, щоб швидко зрозуміти, як він працює.
Просте використання:
class Boy{
private String name;
private double height;
private int age;
//Other code
}
Адаптер для зберігання хлопчикових предметів виглядатиме так:
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 та поставте її, як показано в коді адаптера вище.
Насолоджуйтесь.