RecyclerView: найти последний видимый элемент сразу после создания представления
У меня возникла проблема со следующими методами:
int firstVisibleItemPosition = gridLayoutManager.findFirstVisibleItemPosition();
int lastVisibleItemPosition = gridLayoutManager.findLastVisibleItemPosition();
Моя цель: сохранять аналитические данные о том, какие элементы просматривал пользователь.
Чтобы сделать это, я вызываю эти методы в двух разных сценариях:
-
каждый раз, когда прокрутка переходит в состояние "бездействия" и проверяет, какие видимые элементы. в этом случае я получаю ожидаемые индексы.
-
когда RecyclerView
становится "видимым" для пользователя.
теперь, когда проблема начинается. Я ожидаю, что когда фрагмент, содержащий recylcerView, будет передан onResume()
, то вызов findLastVisibleItemPosition()
вернет видимые элементы. , но в этом случае он возвращает -1. Я предполагаю, что это имеет какое-то отношение к асинхронной загрузке инициализации внутренних элементов recyclerView + адаптера относительно жизненного цикла фрагмента/активности.
отложив этот код на несколько миллисекунд - findLastVisibleItemPosition()
возвращает правильные индексы. но я не хочу откладывать жесткую кодировку с помощью обработчика + delayed runnable, потому что планирование замедленного запуска - это работа над тем, что я действительно хочу сделать: обнаруживать, когда просмотр ресайклера заканчивается раздуванием и рисованием на экране всех представлений, которые могут ноги внутри него.
поэтому мои вопросы в основном:
-
Как я могу определить, когда RecyclerView закончил все инициализацию/измерение/раздувание и рисование его дочерних элементов, которые находятся на экране? (перед любым взаимодействием с пользователем..).
-
Есть ли какой-либо надежный способ хорошей практики, чтобы точно знать, какие элементы в пределах 'отображения ресайклеров действительно отображаются на экране?
Ответы
Ответ 1
Используйте OnChildAttachListener, чтобы определить, когда ресайклеров присоединяет новый держатель. Используйте механизм задержки, чтобы отправить правильные analitycs (\not hardcoded delaybut примерно так:
...
public void run(){
removeCallbacks()
postDelay(sendAnalytics(correctInformation),25);
}
Задержка в 25 мс более надежна, а затем прикрепляется к произвольному производителю.
Ответ 2
Как насчет изменений конфигурации? Если пользователь изменяет ориентацию экрана, видимые элементы тоже изменятся. Факт заключается в том, что видимые элементы постоянно изменяются в соответствии с состоянием RecyclerView
, загруженными данными, положениями прокрутки и текущей конфигурацией экрана.
Лучшее, что вы, вероятно, можете сделать, это создать класс, который постоянно отслеживает надмножество видимых элементов, заставляя его реализовывать интерфейс ItemDecoration
, который вызывается каждый раз, когда RecyclerView
получает redrawn на экране и имеет этот компонент периодически отправляет статистику. Вы вернетесь к новому экземпляру RecyclerView
при изменении конфигурации (сохраняя его состояние).
Так, например, этот компонент мог отслеживать минимальные и максимальные видимые позиции. Сначала это будет -1 для обоих. Затем после того, как данные будут загружены, и первые элементы будут показаны на экране, ItemDecoration
будет вызываться снова, а первое видимое положение позиции теперь будет 0, а последнее видимое положение позиции теперь будет N. После прокрутки значения снова изменятся, Вы должны сохранить минимальное значение FirstVisibleItemPosition и максимальное значение LastVisibleItemPosition, чтобы получить надмножество. После X секунд без изменений или если пользователь перейдет из Activity, вы будете записывать и отправлять эти цифры.
Ответ 3
Что касается ответа на ваш первый вопрос. Лучшее решение для этой проблемы, которое я нашел, это установить прослушиватель разметки в виде ресайклера:
recyclerView.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) {
recyclerView.removeOnLayoutChangeListener(this); //remove layout change listener, you want need it anymore
//do your work here
}
});
Что касается второго вопроса. Вы можете получитьChildCount() и getChildAt (int), чтобы получить информацию о прикрепленном дочернем представлении в настоящее время к recyclerView, но это не значит, что они видны на экране (они могут быть немного за пределами экрана). Чтобы проверить, видны ли они, см. Android: как проверить, виден ли вид внутри ScrollView?