Intereting Posts
Получение всех элементов из ArrayAdapter Android N Предварительный просмотр эмулятора аварии Загрузка пользовательского класса в Dalvik с помощью Gradle (Android New Build System) Какова концептуальная разница между датчиком вектора вращения и датчиком ориентации в Android? Как использовать Gradle для создания файлов проекта Eclipse и Intellij для Android-проектов Как создать анимацию цикла с помощью ViewPropertyAnimator? Не удается установить муравьев правильно для телефонной заставки, используя eclipse и windows 8 Android: проблема с обновлением до Android SDK Tools, версия 7 Каково разумное значение для размера SD-карты для AVD? Как увеличить высоту ScrollView в Android? Одновременный запрос HttpClient с использованием нескольких AsyncTasks Дождитесь окончания анимации другого вида Android-град: buildtoolsVersion vs compileSdkVersion Поверхность была выпущена, когда я пытаюсь установить Disisplay на MediaPlayer Сохранение массива байтов с использованием SharedPreferences

Обновление данных в RecyclerView и сохранение его положения прокрутки

Как обновить данные, отображаемые в RecyclerView (вызывая notifyDataSetChanged на своем адаптере), и убедиться, что положение прокрутки сбрасывается точно там, где оно было?

В случае хорошего ol ' ListView все, что требуется, это получение getChildAt(0) , проверка его getTop() и вызов setSelectionFromTop с setSelectionFromTop же точными данными впоследствии.

Это не представляется возможным в случае RecyclerView .

Я предполагаю, что я должен использовать свой LayoutManager который действительно предоставляет scrollToPositionWithOffset(int position, int offset) , но каков правильный способ получить позицию и смещение?

layoutManager.findFirstVisibleItemPosition() и layoutManager.getChildAt(0).getTop() ?

Или есть более элегантный способ получить работу?

Solutions Collecting From Web of "Обновление данных в RecyclerView и сохранение его положения прокрутки"

У меня совсем другая проблема. И я придумал следующее решение.

Использование notifyDataSetChanged – плохая идея. Вы должны быть более конкретным, тогда RecyclerView сохранит состояние прокрутки для вас.

Например, если вам нужно только обновить или, другими словами, вы хотите, чтобы каждое представление было перегруппировано, просто выполните следующее:

 adapter.notifyItemRangeChanged(0, adapter.getItemCount()); 

Я использую этот. ^ _ ^

 // Save state private Parcelable recyclerViewState; recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState(); // Restore state recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState); 

Это проще, надеюсь, это поможет вам!

EDIT: Чтобы восстановить ту же самую кажущуюся позицию, как и в, сделайте ее похожей на нее, нам нужно сделать что-то немного другое (см. Ниже, как восстановить точное значение scrollY):

Сохраните позицию и смещение следующим образом:

 LinearLayoutManager manager = (LinearLayoutManager) mRecycler.getLayoutManager(); int firstItem = manager.findFirstVisibleItemPosition(); View firstItemView = manager.findViewByPosition(firstItem); float topOffset = firstItemView.getTop(); outState.putInt(ARGS_SCROLL_POS, firstItem); outState.putFloat(ARGS_SCROLL_OFFSET, topOffset); 

Затем восстановите прокрутку следующим образом:

 LinearLayoutManager manager = (LinearLayoutManager) mRecycler.getLayoutManager(); manager.scrollToPositionWithOffset(mStatePos, (int) mStateOffset); 

Это восстанавливает список до его точной видимой позиции. Очевидно, потому что он будет выглядеть одинаково для пользователя, но он не будет иметь такое же значение scrollY (из-за возможных различий в размерах ландшафта и портрета).

Обратите внимание, что это работает только с LinearLayoutManager.

Ниже, как восстановить точный scrollY, который, вероятно, сделает список другим

  1. Примените OnScrollListener так:

     private int mScrollY; private RecyclerView.OnScrollListener mTotalScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); mScrollY += dy; } }; 

Это будет хранить точную позицию прокрутки в любое время в mScrollY.

  1. Сохраните эту переменную в своем Bundle и восстановите ее в состоянии восстановления на другую переменную , мы назовем ее mStateScrollY.

  2. После восстановления состояния и после того, как RecyclerView сбросит все свои данные, прокрутите список:

     mRecyclerView.scrollBy(0, mStateScrollY); 

Вот и все.

Помните, что вы восстанавливаете прокрутку в другую переменную, это важно, потому что OnScrollListener будет вызван с .scrollBy (), а затем установит mScrollY в значение, сохраненное в mStateScrollY. Если вы этого не сделаете, mScrollY будет иметь двойное значение прокрутки (потому что OnScrollListener работает с дельтами, а не с абсолютными прокрутками).

Государственная экономия в деятельности может быть достигнута следующим образом:

 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(ARGS_SCROLL_Y, mScrollY); } 

И чтобы восстановить вызов в вашем onCreate ():

 if(savedState != null){ mStateScrollY = savedState.getInt(ARGS_SCROLL_Y, 0); } 

Государственная экономия на фрагментах работает аналогичным образом, но фактическая экономия состояния требует немного дополнительной работы, но есть много статей, связанных с этим, поэтому у вас не должно возникнуть проблемы с выяснением того, как принципы сохранения scrollY И его восстановление остается прежним.

Я не использовал Recyclerview, но я сделал это в ListView. Пример кода в Recyclerview:

 setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { rowPos = mLayoutManager.findFirstVisibleItemPosition(); 

Это слушатель, когда пользователь прокручивает. Накладные расходы на производительность незначительны. И первая видимая позиция точно такая.

У меня была эта проблема со списком предметов, у каждого из которых было время в минутах, пока они не были «должными» и не нуждались в обновлении. Я бы обновил данные, а потом, позвонил

 orderAdapter.notifyDataSetChanged(); 

И он каждый раз прокручивал вверх. Я заменил это

  for(int i = 0; i < orderArrayList.size(); i++){ orderAdapter.notifyItemChanged(i); } 

И все было хорошо. Ни один из других методов в этой теме не работал для меня. Однако, используя этот метод, он делал каждый отдельный элемент вспышкой, когда он был обновлен, поэтому мне также пришлось поместить его в onCreateView родительского фрагмента

 RecyclerView.ItemAnimator animator = orderRecycler.getItemAnimator(); if (animator instanceof SimpleItemAnimator) { ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); } 

Возможно, это слишком просто, но я делаю именно это, просто позвонив

 recreate(); 

Позиция моего ресайклера сохраняется.

Да, вы можете решить эту проблему, создав конструктор адаптера только один раз, я объясняю здесь часть кодирования:

 if (appointmentListAdapter == null) { appointmentListAdapter = new AppointmentListAdapter(AppointmentsActivity.this); appointmentListAdapter.addAppointmentListData(appointmentList); appointmentListAdapter.setOnStatusChangeListener(onStatusChangeListener); appointmentRecyclerView.setAdapter(appointmentListAdapter); } else { appointmentListAdapter.addAppointmentListData(appointmentList); appointmentListAdapter.notifyDataSetChanged(); } 

Теперь вы можете видеть, что я проверил, что адаптер имеет значение null или нет, и только инициализируется, когда он равен нулю.

Если адаптер не равен нулю, то я уверен, что инициализировал мой адаптер хотя бы один раз.

Поэтому я просто добавлю список в адаптер и вызову notifydatasetchanged.

RecyclerView всегда удерживает последнюю позицию прокрутки, поэтому вам не нужно сохранять последнюю позицию, просто вызывать notifydatasetchanged, просмотр recycler всегда обновляет данные, не переходя к вершине.

Спасибо, Happy Code

Просто верните, если oldPosition и позиция одинаковы;

 private int oldPosition = -1; public void notifyItemSetChanged(int position, boolean hasDownloaded) { if (oldPosition == position) { return; } oldPosition = position; RLog.d(TAG, " notifyItemSetChanged :: " + position); DBMessageModel m = mMessages.get(position); m.setVideoHasDownloaded(hasDownloaded); notifyItemChanged(position, m); }