У меня есть длинный ListView
, который пользователь может прокрутить, прежде чем вернуться к предыдущему экрану. Когда пользователь снова откроет этот ListView
, я хочу, чтобы список был прокручен до той же точки, что и раньше. Любые идеи о том, как достичь этого?Поддержание/сохранение/восстановление позиции прокрутки при возврате в ListView
ответ
Попробуйте это:
// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());
// ...
// restore index and position
mList.setSelectionFromTop(index, top);
Объяснение:
ListView.getFirstVisiblePosition()
возвращает верхний видимый элемент списка. Но этот элемент может быть частично прокручен вне поля зрения, и если вы хотите восстановить точную позицию прокрутки списка, вам нужно получить это смещение. Таким образом, ListView.getChildAt(0)
возвращает View
для элемента верхнего списка, а затем View.getTop() - mList.getPaddingTop()
возвращает относительный смещение от вершины ListView
. Затем, чтобы восстановить положение прокрутки ListView
, мы вызываем ListView.setSelectionFromTop()
с индексом нужного элемента и смещением, чтобы расположить его верхний край от вершины ListView
.
Не совсем понимаю, как это работает. Я использую listView.getFirstVisiblePosition() только и понимаю это, но не уверен, что здесь происходит. Есть ли вероятность краткого объяснения? :) – HXCaine
Итак, ListView.getFirstVisiblePosition() возвращает элемент верхнего видимого списка. Но этот элемент может быть частично прокручен вне поля зрения, и если вы хотите восстановить точную позицию прокрутки списка, вам нужно получить это смещение. Таким образом ListView.getChildAt (0) возвращает представление для элемента верхнего списка, а затем View.getTop() возвращает относительный смещение в верхней части ListView. Затем, чтобы восстановить положение прокрутки ListView, мы вызываем ListView.setSelectionFromTop() с индексом нужного элемента и смещением, чтобы расположить его верхний край от вершины ListView. Все чисто? – ian
Это можно сделать еще проще, используя одну строку для сохранения: 'int index = mList.getFirstVisiblePosition();' и только одна строка для восстановления: 'mList.setSelectionFromTop (index, 0);'. Отличный ответ, хотя (+1)! Я искал элегантное решение этой проблемы. – Phil
Самый простой способ:
/** Save the position **/
int currentPosition = listView.getFirstVisiblePosition();
//Here u should save the currentPosition anywhere
/** Restore the previus saved position **/
listView.setSelection(savedPosition);
Метод setSelection сбросит список к прилагаемому пункту. Если не в режиме касания, элемент будет фактически выбран, если в сенсорном режиме элемент будет отображаться только на экране.
Более сложный подход:
listView.setOnScrollListener(this);
//Implements the interface:
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mCurrentX = view.getScrollX();
mCurrentY = view.getScrollY();
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
//Save anywere the x and the y
/** Restore: **/
listView.scrollTo(savedX, savedY);
была ошибка в вашем ответе. Метод называется setSelection – Janusz
Ty для исправления! –
Идея работает хорошо, но есть псевдопроблема. Первая видимая позиция может быть показана только немного (может быть, только небольшая часть строки), а setSelection() задает эту строку полностью видимой при восстановлении сделан. – rantravee
Parcelable state;
@Override
public void onPause() {
// Save ListView state @ onPause
Log.d(TAG, "saving listview state @ onPause");
state = listView.onSaveInstanceState();
super.onPause();
}
...
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Set new items
listView.setAdapter(adapter);
...
// Restore previous state (including selected item index and scroll position)
if(state != null) {
Log.d(TAG, "trying to restore listview state..");
listView.onRestoreInstanceState(state);
}
}
** Я думаю, что это лучший ответ **, поскольку этот метод восстанавливает точную позицию прокрутки, а не только первый видимый элемент. –
Да, отлично, но с вращением не работает – marekdef
Отличный ответ, но не будет работать при динамической загрузке содержимого и вы хотите сохранить состояние в методе onPause(). – Gio
Я принял решение, предложенное @ (Kirk Woll), и оно работает для меня. Я также видел в исходном коде Android для приложения «Контакты», что они используют подобную технику. Я хотел бы добавить еще некоторые детали: Сверху на моем ListActivity производного класса:
private static final String LIST_STATE = "listState";
private Parcelable mListState = null;
Тогда некоторый метод переопределяет:
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
mListState = state.getParcelable(LIST_STATE);
}
@Override
protected void onResume() {
super.onResume();
loadData();
if (mListState != null)
getListView().onRestoreInstanceState(mListState);
mListState = null;
}
@Override
protected void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
mListState = getListView().onSaveInstanceState();
state.putParcelable(LIST_STATE, mListState);
}
Конечно «LoadData» моя функция для извлечения данных из БД и поместить его в список.
На моем устройстве Froyo это работает как при изменении ориентации телефона, так и при редактировании элемента и возврате его в список.
Отличный код работал очень хорошо с моим списком взглядов, спасибо вам большое ... очень ценю это – user1106888
Спасибо, что он работал нормально ..... – praveenb
Это решение сработало для меня. Другие - нет. Как происходит сохранение/восстановление состояния экземпляра ListView в отношении удаления и вставки элементов в ListView? – Bryan
Я нашел в этом что-то интересное.
Я попытался setSelection и scrolltoXY, но он не работает вообще, список оставался в том же положении, после некоторых проб и ошибок, я получил следующий код, который делает работу
final ListView list = (ListView) findViewById(R.id.list);
list.post(new Runnable() {
@Override
public void run() {
list.setSelection(0);
}
});
Если вместо размещения Runnable вы попробуете runOnUiThread, он тоже не работает (по крайней мере, на некоторых устройствах)
Это очень странное обходное решение для чего-то, что должно быть прямолинейным.
У меня возникла такая же проблема! И 'setSelectionFromTop()' не работает. – ofavre
+1. listnew.post(), не работает на некоторых устройствах, а на некоторых других устройствах он не работает в определенных случаях, но runOnUIThread работает нормально. –
@ Omar, можете ли вы привести некоторые примеры устройств и ОС, на которых это не работает? Я пробовал HTC G2 (2.3.4) и Galaxy Nexus (4.1.2), и он работал над обоими. Ни один из других ответов в этом потоке не работал ни на одном из моих устройств. –
ВНИМАНИЕ! В AbsListView есть ошибка, которая не позволяет корректной работе onSaveState(), если ListView.getFirstVisiblePosition() равно 0.
Так что если у вас есть большие изображения, которые занимают большую часть экрана, и вы перечисляете на второе изображение, но немного из первого показывают, позиция прокрутки не будет сохранена ...
от AbsListView.java:1650 (комментарии) шахтной
// this will be false when the firstPosition IS 0
if (haveChildren && mFirstPosition > 0) {
...
} else {
ss.viewTop = 0;
ss.firstId = INVALID_POSITION;
ss.position = 0;
}
Но в этой ситуации «сверху» в коде ниже будет отрицательное число, которое вызывает другие проблемы, которые мешают государству быть восстановлена правильно. Поэтому, когда «верх» отрицательный, обратитесь к следующему ребенку.
// save index and top position
int index = getFirstVisiblePosition();
View v = getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
if (top < 0 && getChildAt(1) != null) {
index++;
v = getChildAt(1);
top = v.getTop();
}
// parcel the index and top
// when restoring, unparcel index and top
listView.setSelectionFromTop(index, top);
Исправить. У меня такая же проблема с моими большими вещами. – passsy
Большое вам спасибо за это. – tafi
Это работает как шарм, но я не совсем понимаю его. Если первый элемент все еще виден, как это имеет смысл, чтобы получить следующего ребенка? Не следует ли setSelectionFromTop с новым индексом вызывать отображение списка, начиная со второго ребенка? Как я все еще вижу первый? – tafi
Опубликовать это, потому что я удивлен, что никто не упомянул об этом.
После того, как пользователь нажмет кнопку «Назад», он вернется в список в том же состоянии, в каком он вышел.
Этот код будет переопределять кнопку «вверх», чтобы вести себя так же, как кнопка «Назад», поэтому в случае Listview -> Details -> Back to Listview (и других параметров) это простейший код для поддержки прокрутки и содержимого в списке.
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return(true);
}
return(super.onOptionsItemSelected(item)); }
Внимание: Если вы можете перейти на другой вид деятельности от деталей деятельности до кнопки вернет вас к этой деятельности, так что вы должны будете манипулировать историей BackButton для того, чтобы это работало.
Не просто android:saveEnabled="true"
в описании ListView xml достаточно?
android: saveEnabled по умолчанию установлено значение true. Это ничего не делает. – Brad
№. этого недостаточно, вы должны следовать http://stackoverflow.com/questions/3014089/maintain-save-restore-scroll-position-when-returning-to-a-listview?answertab=active#tab-top ИЛИ http: //stackoverflow.com/questions/3014089/maintain-save-restore-scroll-position-when-returning-to-a-listview?answertab=active#answer-5688490 –
Если вы используете фрагменты, размещенные на активности вы можете сделать что-то вроде этого:
public abstract class BaseFragment extends Fragment {
private boolean mSaveView = false;
private SoftReference<View> mViewReference;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (mSaveView) {
if (mViewReference != null) {
final View savedView = mViewReference.get();
if (savedView != null) {
if (savedView.getParent() != null) {
((ViewGroup) savedView.getParent()).removeView(savedView);
return savedView;
}
}
}
}
final View view = inflater.inflate(getFragmentResource(), container, false);
mViewReference = new SoftReference<View>(view);
return view;
}
protected void setSaveView(boolean value) {
mSaveView = value;
}
}
public class MyFragment extends BaseFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setSaveView(true);
final View view = super.onCreateView(inflater, container, savedInstanceState);
ListView placesList = (ListView) view.findViewById(R.id.places_list);
if (placesList.getAdapter() == null) {
placesList.setAdapter(createAdapter());
}
}
}
private Parcelable state;
@Override
public void onPause() {
state = mAlbumListView.onSaveInstanceState();
super.onPause();
}
@Override
public void onResume() {
super.onResume();
if (getAdapter() != null) {
mAlbumListView.setAdapter(getAdapter());
if (state != null){
mAlbumListView.requestFocus();
mAlbumListView.onRestoreInstanceState(state);
}
}
}
Это достаточно
Добавить более подробную информацию pls – Rajesh
Привет, будет ли ваш код выше help меня с списком RecyclerView, где instancestate не сохраняется между действиями? Я разместил здесь следующий вопрос: http://stackoverflow.com/questions/35413495/android-how-do-return-to-newly-created-recyclerview-list? – AJW
При сохранении/восстановлении положение прокрутки ListView
себя вы по существу дублируя функциональность, уже реализованную в инфраструктуре Android. ListView
отлично восстанавливает положение прокрутки, за исключением одного оговорки: как упоминалось в @aaronvargas, есть ошибка в AbsListView
, которая не позволит восстановить точную позицию прокрутки для первого элемента списка. Тем не менее, лучший способ восстановить положение прокрутки - не восстановить его. Рамка для Android сделает это лучше для вас. Просто убедитесь, что вы встретились следующими условиями:
- убедитесь, что вы не вызвали
setSaveEnabled(false)
метода и не установленыandroid:saveEnabled="false"
атрибута для списка в файле макет XML - для
ExpandableListView
переопределенияlong getCombinedChildId(long groupId, long childId)
метода так, что он возвращает положительным длинный номер (реализация по умолчанию в классеBaseExpandableListAdapter
возвращает отрицательное число). Вот примеры:
.
@Override
public long getChildId(int groupPosition, int childPosition) {
return 0L | groupPosition << 12 | childPosition;
}
@Override
public long getCombinedChildId(long groupId, long childId) {
return groupId << 32 | childId << 1 | 1;
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getCombinedGroupId(long groupId) {
return (groupId & 0x7FFFFFFF) << 32;
}
- , если
ListView
илиExpandableListView
используется в фрагменте не воссоздать фрагмент на активности отдыха (после поворота экрана, например).Получите фрагмент с помощью методаfindFragmentByTag(String tag)
. - удостоверьтесь, что у
ListView
естьandroid:id
и он уникален.
Чтобы избежать вышеупомянутого нюанса с первым элементом списка вы можете изготовить адаптер, как он возвращает специальный фиктивный ноль пикселей вида высоты для ListView
в положении 0. Вот простой пример проект показывает ListView
и ExpandableListView
восстановить их штраф пока их позиции прокрутки не будут явно сохранены/восстановлены. Точная позиция прокрутки восстанавливается отлично даже для сложных сценариев с временным переключением на другое приложение, двойным поворотом экрана и переключением обратно в тестовое приложение. Обратите внимание: если вы явно выходите из приложения (нажав кнопку «Назад»), положение прокрутки не будет сохранено (так же как все остальные виды не сохранят свое состояние). https://github.com/voromto/RestoreScrollPosition/releases
ЛУЧШЕЕ РЕШЕНИЕ IS:
// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());
// ...
// restore index and position
mList.post(new Runnable() {
@Override
public void run() {
mList.setSelectionFromTop(index, top);
}
});
ВЫ ДОЛЖНЫ ЗВОНИТЕ В ПОСТ И в резьбе!
Для деятельности, полученной из ListActivity, который реализует LoaderManager.LoaderCallbacks с использованием SimpleCursorAdapter он не работает, чтобы восстановить положение в OnReset(), потому что активность была почти всегда перезапущена и адаптер был перезагружен, когда деталь вид был закрыт , Хитрость в том, чтобы восстановить положение в onLoadFinished():
в onListItemClick():
// save the selected item position when an item was clicked
// to open the details
index = getListView().getFirstVisiblePosition();
View v = getListView().getChildAt(0);
top = (v == null) ? 0 : (v.getTop() - getListView().getPaddingTop());
в onLoadFinished():
// restore the selected item which was saved on item click
// when details are closed and list is shown again
getListView().setSelectionFromTop(index, top);
в onBackPressed():
// Show the top item at next start of the app
index = 0;
top = 0;
Для некоторых, кто ищет решение этой проблемы, корень проблемы может быть в том месте, где вы устанавливаете адаптер списка видов. После того, как вы установите адаптер в списке, он сбрасывает положение прокрутки. Просто подумать. Я переместил адаптер в мой onCreateView после того, как мы захватили ссылку на список, и он решил проблему для меня. =)
Вы можете сохранить состояние прокрутки после перезагрузки, если вы сохраните состояние до перезагрузки и восстановления после него. В моем случае я сделал асинхронный сетевой запрос и перезагрузил список в обратном вызове после его завершения. Здесь я восстанавливаю состояние. Образец кода - это Котлин.
val state = myList.layoutManager.onSaveInstanceState()
getNewThings() { newThings: List<Thing> ->
myList.adapter.things = newThings
myList.layoutManager.onRestoreInstanceState(state)
}
- 1. Сохранение позиции прокрутки в ListView
- 2. Изменение точной прокрутки-позиции в Listview
- 3. Восстановление позиции при возврате в ListFragment
- 4. Позиции позиции ListView повторяются
- 5. при изменении положения кнопки прокрутки в ListView
- 6. Listview удваивается при возврате к нему
- 7. ListView не обновляется при возврате к активности
- 8. Перезагрузка ListView при возврате к фрагменту
- 9. Исправить положение прокрутки при нажатии кнопки в определенной позиции прокрутки
- 10. Сохранение позиции списка в android
- 11. Точная позиция прокрутки ListView
- 12. UITableView начало прокрутки позиции
- 13. Android - Listview Позиции позиции уменьшаются
- 14. Ведение позиции прокрутки в WebView
- 15. ReactNative ListView установка начальной позиции прокрутки после загрузки данных
- 16. Синхронизировать две позиции ListView
- 17. Сохранение позиции прокрутки при открытии JQuery диалогового
- 18. Сохранение позиции прокрутки в Ember
- 19. ListView Переключение позиции позиции и нарушение при прокрутке
- 20. Как избежать прокрутки TDbgrid при возврате в предыдущее местоположение
- 21. ListView - поведение индекса и позиции при перезапуске()
- 22. Неправильная позиция позиции ListView
- 23. Переключение между сценами, но сохранение позиции игрока при возврате?
- 24. восстановление позиции прокрутки uitableview
- 25. Установка позиции полосы прокрутки
- 26. JQuery позиции магазина прокрутки
- 27. одометра на позиции прокрутки
- 28. Вычисление позиции прокрутки
- 29. получить прокрутки позиции в контейнере
- 30. Поддержание позиции прокрутки в списке
Я думаю, что решения, упомянутые Евгений Мымрин/Giorgio Barchiesi лучше, чем принято отвечать –
Приведенное решение по «Giorgio Barchiesi» работал для меня. Другие решения не помогли мне. – Bryan