RecyclerViewで特定のアイテムを更新/更新する方法


111

で特定のアイテムを更新しようとしていRecyclerViewます。

ストーリー:ユーザーがアイテムをクリックするたびに、が表示されますAlertDialog。ユーザーは[OK]ボタンをクリックしてテキストを入力できます。このテキストをこのアイテムに表示して非表示にしたい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も変更します!

特定のitemViewをクリックして正しく変更するにはどうすればよいですか?

回答:


98

notifyItemChanged(int position)RecyclerView.Adapterクラスのメソッドを使用できます。ドキュメントから:

登録されているオブザーバーに、位置にあるアイテムが変更されたことを通知します。notifyItemChanged(position、null);を呼び出すことと同等です。

これはアイテム変更イベントであり、構造変更イベントではありません。これは、位置にあるデータの反映が古く、更新する必要があることを示しています。位置にあるアイテムは同じアイデンティティを保持します。

あなたはすでにポジションを持っているので、それはあなたのために働くはずです。


9
私はすでにそれを使用しましたが、位置0を更新したい場合、位置
0、9、19

コメントを理解できませんでした。どの位置が更新されていますか?0、9、または0と9の間の範囲?
エドソンメネガッティ2015

いいえ、範囲ではありません。アイテムを更新するたびに、不要なアイテムも更新されます
Elgendy

@Learner ViewHolderを位置0で更新すると、更新されたままになります。RecyclerViewはそのViewHolder をリサイクルし、ポジション9に使用するため、これらの変更が表示されます。代わりに、このテキストをonBindViewHolder()で設定することをお勧めします。このようにして、ViewHolderがリサイクルされるたびに、その位置を確認してテキストを設定したり、画像を表示したりすることができます。
Cliabhach

@Cliabhachでも変更を行う同じ問題onBindViewHolder()
Choletski

39

単一のアイテムを更新

  1. データアイテムを更新する
  2. アダプタに変更を通知します notifyItemChanged(updateIndex)

「羊」が「羊が好き」と表示されるように変更します。

単一のアイテムを更新

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

より多くの例での私の完全な答えはここにあります


更新されたデータスイッチを先頭にしたい場合の方法
Choy

@Choy、データを更新した後、データをインデックス0に移動できます。このアイテムの
Suragch

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
あと1つステップを実行しています。位置の要素を置き換えて、アイテムnotifyItemChanged(position);を呼び出します。
toshkinl 2017年

@toshkinlデータがJSONObjectから来ていることをどのように知ることができますか?ポジションなし?
olajide

7

変更が必要なアイテムの位置をキャッチしてからアダプター呼び出しでこの問題を解決する必要がありました

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

、これにより、この特定の位置にあるこの特定のアイテムのonBindViewHolder(ViewHolderholder、int position)が呼び出されます。


2

以下の解決策は私のために働きました:

RecyclerViewアイテムで、ユーザーはボタンをクリックしますが、TextViewなどの別のビューは、アダプターに直接通知することなく更新されます。

notifyDataSetChanged()メソッドを使用せずにこれの適切な解決策を見つけました。このメソッドはrecyclerViewのすべてのデータを再ロードするため、アイテム内に画像またはビデオがある場合、それらは再ロードされ、ユーザーエクスペリエンスは良くありません。

以下は、ImageViewのようなアイコンをクリックし、1つの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

個人的にはうまくいった方法の1つは、recyclerviewのアダプターメソッドを使用して、アイテムの変更を処理することです。

これは、これに似た方法で行われ、カスタムリサイクラーのビューで次のようにメソッドを作成します。

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);
}

私の回避策は、(要素、位置)のマップインスタンスを作成することです

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

1つのオブジェクトを作成し、それをアダプターで使用するリストに追加している場合、アダプターでリストの1つの要素を変更すると、他のすべての項目も変更されます。つまり、参照に関するすべてが変更され、リストは変更されません。その単一のオブジェクトの個別のコピーを保持します。


-5

RecyclerViewアダプターには、ArrayListとaddItemsToList(items)、リスト項目をArrayListに追加する1つのメソッドが必要です。次に、adapter.addItemsToList(items)動的に呼び出すことでリスト項目を追加できます。すべてのリスト項目をArrayListに追加したら、を呼び出しadapter.notifyDataSetChanged()てリストを表示できます。

notifyDataSetChangedRecyclerViewのアダプターでを使用できます


はい、私はデータのためにArrayListを持っています、それは問題なく機能します、このリストの特定の
既存の

更新しているアイテムの位置が必要です。新しいアイテムをmList.add(position).setName( "new name");のようなそれぞれの位置に配置する必要があります。次に、mAdapter.notifyDataSetChanged();を使用します。
Nooruddin Lakhani、2015

4
この回答は、単一のアイテムを更新したいという要望を無視しています。notifyDataSetChanged()の呼び出しは、データセット全体が変更されたときにのみ行う必要があります。
Mark McClelland、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.