2015-04-16 6 views
65

Поскольку новая версия библиотеки поддержки (22.x) метод getPosition() класса RecyclerView.ViewHolder устарел вместо методов, упомянутых в теме. Я действительно не понимаю, как читать документы. Не могли бы кто-нибудь объяснить разницу в условиях неспециалиста, пожалуйста?RecyclerView.ViewHolder - getLayoutPosition vs getAdapterPosition

У меня есть следующий прецедент - я даю моему адаптеру список, а также хочу иметь возможность связывать дополнительную информацию для каждого элемента списка. У меня есть сопоставление позиции для дополнительного, и отображение доступно для держателей, чтобы они могли получить дополнительные для своей позиции и делать с ним вещи. В держателе, какой метод я должен использовать?

Что происходит с позициями держателя, когда элементы списка с индексами 0 и 1 переключаются местами? Что возвращают методы?

ответ

78

Это сложная ситуация, извините, что документов недостаточно.

При изменении содержимого адаптера (и вы вызываете notify***()) RecyclerView запрашивает новый макет. С этого момента, пока система макета не решит рассчитать новый макет (< 16 мс), расположение макета и положение адаптера могут не совпадать, так как макет еще не изменил изменения адаптера.

В вашем случае использования, поскольку ваши данные связаны с содержимым вашего адаптера (и я предполагаю, что данные будут изменены одновременно с изменениями адаптера), вы должны использовать adapterPosition.

Будьте осторожны, если вы вызываете notifyDataSetChanged(), потому что это делает недействительным все, RecyclerView не знает, что позиция адаптера ViewHolder до вычисления следующего макета. В этом случае getAdapterPosition() вернет RecyclerView#NO_POSITION (-1).

Но позволяет сказать, что если вы назвали notifyItemInserted(0), то getAdapterPosition() из ViewHolder, который ранее был в положении 0 начнется сразу возвращение 1. Таким образом, пока вы отправляете подробные уведомления о событиях, вы всегда в хорошем состоянии (мы знаем положение адаптера, даже если новый макет еще не рассчитан).

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

Edit Для Когда Компоновка установки Хороша

Допустим, вы используете LinearLayoutManager и хотите получить доступ к ViewHolder выше текущего щелкнули пункта. В этом случае вы должны использовать расположение макета, чтобы получить элемент выше.

mRecyclerView.findViewHolderForLayoutPosition(myViewHolder.getLayoutPosition() - 1) 

Вы должны использовать расположение макета, так как оно соответствует тому, что пользователь в настоящее время видит на экране.

+1

Я немного поиграл, и получается, что метод getAdapterPosition() всегда возвращает -1 на меня. Я отлаживал его, и причина в том, что код в методе (конечный ViewParent parent = itemView.getParent(); if (! (Parent instanceof RecyclerView)) {return -1;} всегда попадает в блок if, т. Е. Просмотр recycler не является родителем моего представления ячеек.Как это может быть? Мой код для создания владельца: return MyViewHolder (LayoutInflater.from (viewGroup.getContext()). inflate (R.layout.test_list_item, viewGroup, false)); (Продолжение в другом комментарии.) – wujek

+0

Когда я изменяю код для вызова inflate (R.layout.test_list_item, viewGroup, true); (обратите внимание на true для «attach to root»), Android throws: java.lang.IllegalStateException: указанный ребенок уже имеет родителя. Сначала вы должны вызвать removeView() родителя ребенка. Итак, каков правильный способ создания держателя вида с представлением, которое правильно привязано к просмотру ресайклеров? Как ни странно, даже если getAdapterPosition() возвращает -1, потому что родительский элемент имеет значение null, все остальное работает нормально. – wujek

+1

Булевым параметром в макетном инфляторе является «addToParent». Он должен быть ложным, потому что ответственность LayoutManager заключается в его добавлении. Я думаю, что вы вызываете getAdapterPosition в onBind, где вы уже прошли позицию. Технически, держатель представления представляет это положение после того, как onBind возвращается. Btw, мы обновили положение getAdapter, чтобы вернуть действительное положение (если возможно), даже если оно отсоединено, оно будет выпущено в ближайшее время. – yigit

Смежные вопросы