Як я можу створити список, коли після досягнення кінця списку мене отримують сповіщення, щоб я міг завантажити більше елементів?
Як я можу створити список, коли після досягнення кінця списку мене отримують сповіщення, щоб я міг завантажити більше елементів?
Відповіді:
Одним із варіантів є впровадження 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 та поставте її, як показано в коді адаптера вище.
Насолоджуйтесь.