Я использую RecyclerView с CardView для отображения списка карт. Каждая карта имеет 2 linearLayout (1 для заголовка и 1 для разворота, вторая - только при нажатии карты).
Когда я изменяю приоритет карты, карта перемещается в новую позицию списка (я изменяю ее позицию в "массиве" элемента, а затем вызываю адаптер .notifyItemMoved(oldPosition, newPosition)), и он Я также называю RecyclerView.scrollToPosition(newPosition), чтобы показать новую позицию в списке.
Теперь проблема, я хочу развернуть карту после того, как я переместил ее в новую позицию, и для этого мне нужна линейная линейка внутри карты, они находятся в ViewHolder, которые держат карту. Я пытаюсь использовать RecyclerView.findViewHolderAtPosition(newPosition), но он возвращает ViewHolder только в том случае, если карта видна там, где я был до "scrollTo", если карта выведена из этих "видимых карт", она всегда возвращает null. (Я также использую mRecyclerView.setItemViewCacheSize(myDataset.size()) для решения других проблем, поэтому я ожидал правильного ViewHolder, даже если он не в зрении)
public void moveTask(int oldPosition, int position, Task task) {
if (oldPosition < position) {
myDataset.add(position, task);
myDataset.remove(oldPosition);
} else {
myDataset.remove(oldPosition);
myDataset.add(position, task);
}
mAdapter.notifyItemMoved(oldPosition, position);
mAdapter.notifyDataSetChanged();
mRecyclerView.smoothScrollToPosition(position);
MyViewHolder holder =(MyViewHolder)mRecyclerView.findViewHolderForPosition(position);
mAdapter.expandCard(holder);
}
mAdapter.notifyDataSetChanged() не следует вызывать (notifyItemMoved должно быть достаточно), но иногда это не работает без него.
expandCard просто устанавливает видимость линейного расширения "expandable" в Visible, а другой linearLayout "расширяемый" уже доступен для Gone.
Что я могу сделать, чтобы это сработало? Я делаю это совершенно неправильно? Надеюсь, я объяснил проблему понятным образом. Если мне нужно лучше объяснить, как я что-то делаю, я всегда здесь, спасибо за помощь.
Итак, я решил это, я думал не так.
Вы не должны пытаться найти правильный ViewHolder из "снаружи", как я делал, а просто "развернуть" его в OnBindViewHolder, когда одна привязка является правильной.
В moveTask, который я делал, я делал это раньше, но я устанавливаю позицию открываемой карты:
public void moveTask(int oldPosition, int position, Task task) {
if (oldPosition < position) {
myDataset.add(position, task);
myDataset.remove(oldPosition);
} else {
myDataset.remove(oldPosition);
myDataset.add(position, task);
}
mAdapter.notifyItemMoved(oldPosition, position);
//this is the important line, it set the variable
//openPos with the right number
mAdapter.setOpenPos(position);
mAdapter.notifyItemChanged(position);
mRecyclerView.scrollToPosition(position);
}
а затем в адаптере onBindViewHolder я проверяю, когда я нахожусь в правильном положении:
@Override
public void onBindViewHolder(MyViewHolder holder, int pos) {
--set other fields--
// expand the right card
// if it the first open it
if (pos == 0) {
holder.expand(holder.mHeader, holder.mExpanded);
// and collapse the opened one
if (openPos != -1 && openPos != pos) {
open.collapse(open.mHeader, open.mExpanded, true);
}
isFirst = holder;
open = holder;
openPos = 0;
}
// I'm in the position of the one I should open
// expand it
else if (openPos != -1 && pos == openPos) {
holder.expand(holder.mHeader, holder.mExpanded);
// and if I changed openPos with setOpenPos()
// collapse the "old" open card
if(openPos != open.getPosition()){
open.collapse(open.mHeader, open.mExpanded, true);
}
open = holder;
}
// if I'm in another card just collapse it
else {
holder.collapse(holder.mHeader, holder.mExpanded, true);
}
}
И, как это, отлично работает. Он должен работать даже без использования "setItemViewCacheSize", но у него есть другие странные проблемы без него, поэтому на данный момент я его оставляю.
Прежде всего, вы не должны называть mRecyclerView.setItemViewCacheSize(myDataset.size())
. Это означает создание ViewHolder для каждого элемента в списке, не сильно отличающегося от использования LinearLayout.
Во-вторых, findViewHolderForPosition
проверяет только детей. Это будет добавлено в документы для уточнения.
В вашем случае mAdapter.notifyItemMoved
достаточно не, потому что RV не знает, что он должен переподчинить элемент. Вам также нужно вызвать notifyItemChanged
, чтобы RV знал, что представление должно быть отскоком.
Создайте два типа представления (для простоты вам не обязательно). Один рухнул, один расширился. Затем, когда вы хотите переместить и развернуть элемент, вызовите:
public void moveTask(int oldPosition, int position, Task task) {
if (oldPosition < position) {
myDataset.add(position, task);
myDataset.remove(oldPosition);
} else {
myDataset.remove(oldPosition);
myDataset.add(position, task);
}
task.expanded = true;
mAdapter.notifyItemMoved(oldPosition, position);
mAdapter.notifyItemChanged(position);
}
//adapter
getItemViewType(int position) {
return myDataset.get(position).expanded ? TYPE_EXPANDED : TYPE_HEADER;
}
Поскольку вы вызвали notifyItemChanged
, RV перекроет это представление.