Як оновити / оновити конкретний елемент у RecyclerView


112

Я намагаюся оновити конкретний елемент у RecyclerView.

Історія: Щоразу, коли користувач натискає на предмет, він відображається AlertDialog. Користувач може ввести текст, натиснувши кнопку ОК. Я хочу показати цей текст у цьому пункті та показати невидимий ImageView- оголошено у XML та адаптері ViewHolder-

Я використовував цю функцію в AlertDialogпозитивній кнопці для оновлення елемента:

private void updateListItem(int position) {
  View view = layoutManager.findViewByPosition(position);
  ImageView medicineSelected = (ImageView) view.findViewById(R.id.medicine_selected);
  medicineSelected.setVisibility(View.VISIBLE);
  TextView orderQuantity = (TextView) view.findViewById(R.id.order_quantity);
  orderQuantity.setVisibility(View.VISIBLE);
  orderQuantity.setText(quantity + " packet added!");

  medicinesArrayAdapter.notifyItemChanged(position);
}

Але цей код не тільки змінює itemView у пройденому положенні, але й змінює деякі інші itemView (s) також!

Як я можу правильно змінити конкретний itemView, натиснувши на нього?

Відповіді:


98

Ви можете використовувати notifyItemChanged(int position)метод із класу RecyclerView.Adapter. З документації:

Повідомте будь-яких зареєстрованих спостерігачів, що пункт у позиції змінився. Еквівалент виклику notifyItemChanged (позиція, нуль) ;.

Це подія зміни пункту, а не подія структурної зміни. Це вказує на те, що будь-яке відображення даних у позиції застаріло і повинно бути оновлене. Елемент у позиції зберігає ту саму ідентичність.

Оскільки у вас вже є посада, це повинно працювати для вас.


9
Я вже використовував це, але якщо я хочу оновити позицію 0, це оновлення позиції 0, 9, 19, ...
Elgendy

Вибачте, не зрозумів ваш коментар. Яка позиція оновляється? 0, 9 або діапазон між 0 і 9?
Едсон Менегатті

Ні, це не діапазон, кожен раз, коли я
оновлюю

@Learner Коли ви оновлюєте ViewHolder на позиції 0, він залишається оновленим. RecyclerView переробить цей ViewHolder і використає його для позиції 9, тож ви побачите ці зміни там. Я рекомендую замість цього встановити цей текст у onBindViewHolder () - таким чином, при переробці ViewHolder ви можете перевірити його положення та встановити текст або зробити зображення видимим чи будь-яким правильним.
Кліабхач

@Cliabhach все ж проблема, що робить зміни вonBindViewHolder()
Чолецькі

39

Оновіть один елемент

  1. Оновіть елемент даних
  2. Повідомте адаптер про зміну за допомогою notifyItemChanged(updateIndex)

Приклад

Змініть пункт «Вівці» так, щоб він писав «Мені подобаються вівці».

Оновіть один елемент

String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);

Моя повна відповідь з більшою кількістю прикладів тут .


як це зробити, якщо я хочу оновити перемикач даних на початок
Чой,

@Choy, після оновлення даних ви можете перемістити їх до індексу 0. Див. Розділ Переміщення одного предмета цього пункту
Сурагч

11

Додайте змінений текст до списку даних вашої моделі

mdata.get(position).setSuborderStatusId("5");
mdata.get(position).setSuborderStatus("cancelled");
notifyItemChanged(position);

10

Я думаю, що у мене є ідея, як з цим боротися. Оновлення - це те саме, що видалення та заміна в точній позиції. Тому я спочатку видаляю елемент із цього положення за допомогою наведеного нижче коду:

public void removeItem(int position){
    mData.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, mData.size());
}

і тоді я додав би елемент у цій конкретній позиції, як показано нижче:

public void addItem(int position, Landscape landscape){
    mData.add(position, landscape);
    notifyItemInserted(position);
    notifyItemRangeChanged(position, mData.size());
}

Я намагаюся це зараз реалізувати. Я б дав вам відгук, коли я закінчу!


2
Ви робите один додатковий крок. Просто замініть елемент на позицію та виклик елемента notifyItemChanged (позиція);
toshkinl

@toshkinl Як ви могли знати, коли дані надходять від JSONObject? без позиції?
olajide

7

Я вирішив цю проблему, ввівши позицію елемента, який потрібно змінити, а потім під час виклику адаптера

public void refreshBlockOverlay(int position) {
    notifyItemChanged(position);
}

, це викликає onBindViewHolder (власник ViewHolder, позиція int) для цього конкретного елемента в цій конкретній позиції.


2

Нижче рішення працювало для мене:

На елементі RecyclerView користувач натисне кнопку, але інший вид, як-от TextView, оновиться без прямого повідомлення про адаптер:

Я знайшов хороше рішення для цього, не використовуючи метод notifyDataSetChanged (), цей метод перезавантажує всі дані recilerView, тому якщо у вас є зображення або відео всередині елемента, вони перезавантажуються, а досвід користувача не буде корисним:

Ось приклад клацання піктограми типу ImageView як і оновлення лише одного TextView (можливо оновити більше перегляду тим самим елементом), щоб показати, як оновлення підрахунку після додавання +1:

// View holder class inside adapter class
public class MyViewHolder extends RecyclerView.ViewHolder{

    ImageView imageViewLike;

    public MyViewHolder(View itemView) {
         super(itemView);

        imageViewLike = itemView.findViewById(R.id.imageViewLike);
        imageViewLike.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int pos = getAdapterPosition(); // Get clicked item position
                TextView tv = v.getRootView().findViewById(R.id.textViewLikeCount); // Find textView of recyclerView item
                resultList.get(pos).setLike(resultList.get(pos).getLike() + 1); // Need to change data list to show updated data again after scrolling
                tv.setText(String.valueOf(resultList.get(pos).getLike())); // Set data to TextView from updated list
            }
        });
    }

1

Спосіб, який особисто працював для мене, - це використання адаптерних методів recilerview для усунення змін у його елементах.

Це було б схожим на це, створивши метод на думку власного переробника, приблизно таким:

public void modifyItem(final int position, final Model model) {
    mainModel.set(position, model);
    notifyItemChanged(position);
}

0

У вашому класі адаптерів у методі onBindViewHolder встановіть ViewHolder на setIsRecyclable (false), як у наведеному нижче коді.

@Override
public void onBindViewHolder(RecyclerViewAdapter.ViewHolder p1, int p2)
{
    // TODO: Implement this method
    p1.setIsRecyclable(false);

    // Then your other codes
}

0

вам просто потрібно додати наступний код у діалоговому вікні попередження про збереження клацання

          recyclerData.add(position, updateText.getText().toString());
          recyclerAdapter.notifyItemChanged(position);

0

Проблема полягає в тому, RecyclerView.Adatperщо не передбачено жодних методів, які повертають індекс елемента

public abstract static class Adapter<VH extends ViewHolder> {
  /**
   * returns index of the given element in adapter, return -1 if not exist
   */
  public int indexOf(Object elem);
}

Моє вирішення - створити екземпляр карти для (елемент, позиція) s

public class FriendAdapter extends RecyclerView.Adapter<MyViewHolder> {
  private Map<Friend, Integer> posMap ;
  private List<Friend> friends;

  public FriendAdapter(List<Friend> friends ) {
    this.friends = new ArrayList<>(friends);
    this.posMap = new HashMap<>();
    for(int i = 0; i < this.friends.size(); i++) {
      posMap.put(this.friends.get(i), i);
    }
  }

  public int indexOf(Friend friend) {
    Integer position = this.posMap.get(elem);
    return position == null ? -1 : position;
  }
  // skip other methods in class Adapter
}
  • тип елемента (тут клас Friend) повинен реалізувати hashCode()і equals()тому, що він є ключовим у хешмапі.

коли елемент змінився,

  void someMethod() {
    Friend friend = ...;
    friend.setPhoneNumber('xxxxx');

    int position = friendAdapter.indexOf(friend);
    friendAdapter.notifyItemChanged(position);

  }

Добре визначити хелперний метод

public class FriendAdapter extends extends RecyclerView.Adapter<MyViewHolder> {

  public void friendUpdated(Friend friend) {
    int position = this.indexOf(friend);
    this.notifyItemChanged(position);
  }
}

Екземпляр карти ( Map<Friend, Integer> posMap) не обов'язково обов'язковий. Якщо карта не використовується, в циклі по всьому списку можна знайти позицію елемента.


-1

Це теж моя остання проблема. У цьому моєму рішенні я використовую Модель даних та адаптер для свого RecyclerView

 /*Firstly, register your new data to your model*/
 DataModel detail = new DataModel(id, name, sat, image);

 /*after that, use set to replace old value with the new one*/
 int index = 4;
 mData.set(index, detail);

 /*finally, refresh your adapter*/
 if(adapter!=null)
    adapter.notifyItemChanged(index);

-1

якщо ви створюєте один об'єкт і додаєте його до списку, який ви використовуєте у своєму адаптері, коли ви змінюєте один елемент свого списку в адаптері, всі ваші інші елементи теж змінюються іншими словами, все про посилання, і ваш список не зберігати окремі копії цього єдиного об'єкта.


-5

У адаптері RecyclerView у вас повинен бути ArrayList, а також один спосіб addItemsToList(items)додавання елементів списку до ArrayList. Потім ви можете додавати елементи списку, зателефонувавши adapter.addItemsToList(items)динамічно. Після того, як всі елементи списку додані до ArrayList, ви можете зателефонуватиadapter.notifyDataSetChanged() щоб відобразити свій список.

Ви можете використовувати notifyDataSetChangedв адаптері для RecyclerView


так, у мене є ArrayList для даних, він працює без проблем, моя проблема в оновленні конкретного -існуючого елемента в цьому списку
Elgendy

у вас повинна бути позиція елемента, яка оновлюється, тоді вам просто потрібно поставити новий елемент у відповідному положенні, як mList.add (позиція) .setName ("нове ім'я"); потім використовуйте mAdapter.notifyDataSetChanged ();
Норуддін Лахані

4
Ця відповідь ігнорує бажання оновити окремий елемент. Виклик notifyDataSetChanged () повинен здійснюватися лише тоді, коли змінюється весь набір даних.
Марк МакКлелленд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.