RecyclerView'da belirli bir öğe nasıl güncellenir / yenilenir


112

İçindeki belirli öğeyi yenilemeye çalışıyorum RecyclerView.

Hikaye: Kullanıcı öğeye tıkladığında gösterilir AlertDialog. Kullanıcı ok düğmesine tıklayarak bir metin yazabilir. Bu metni bu öğede göstermek ve görünmez göstermek istiyorum ImageView- XML ​​ve adaptörde beyan edildi ViewHolder-

Bu işlevi AlertDialog, öğeyi güncellemek için Pozitif Düğmede kullandım:

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

Ancak bu kod yalnızca geçilen konumdaki itemView'ı değiştirmekle kalmaz, aynı zamanda diğer bazı itemView (ları) 'nı da değiştirir!

Belirli bir itemView'a tıklayarak doğru bir şekilde nasıl değiştirmeliyim?

Yanıtlar:


98

Sen kullanabilirsiniz notifyItemChanged(int position)RecyclerView.Adapter sınıfından yöntemi. Belgelerden:

Kayıtlı gözlemcilere pozisyondaki kalemin değiştiğini bildirin. NotifyItemChanged (position, null); 'ı çağırmaya eşdeğerdir.

Bu bir öğe değişikliği olayıdır, yapısal bir değişiklik olayı değildir. Konumdaki verilerin herhangi bir yansımasının güncel olmadığını ve güncellenmesi gerektiğini gösterir. Konumdaki öğe aynı kimliği korur.

Zaten pozisyona sahip olduğunuz için, sizin için çalışmalıdır.


9
Zaten kullandım ama 0 konumunu güncellemek istersem, 0, 9, 19, ... konumunu güncelliyor.
Elgendy

Üzgünüm, yorumunuzu anlamadım. Hangi pozisyon güncelleniyor? 0, 9 veya 0 ile 9 arasındaki aralık?
Edson Menegatti

Hayır, aralık değil, öğeyi her güncellediğimde, istenmeyen öğeleri de yeniliyor
Elgendy

@Learner ViewHolder'ı 0 konumunda güncellediğinizde, güncel kalır. RecyclerView, bu ViewHolder'ı geri dönüştürür ve onu konum 9 için kullanır, böylece bu değişiklikleri orada görürsünüz. Bunun yerine bu metni onBindViewHolder () içinde ayarlamanızı öneririm - bu şekilde, bir ViewHolder geri dönüştürüldüğünde konumunu kontrol edebilir ve metni ayarlayabilir veya resmi görünür yapabilir veya doğru şekilde yapabilirsiniz.
Cliabhach

@Cliabhach hala aynı problemde değişiklik yapıyoronBindViewHolder()
Choletski

39

Tek öğeyi güncelle

  1. Veri öğesini güncelleyin
  2. Bağdaştırıcıya değişikliği ile bildirin. notifyItemChanged(updateIndex)

Misal

"Koyun" öğesini "Koyunları severim" yazacak şekilde değiştirin.

Tek öğeyi güncelle

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

Daha fazla örnekle tam cevabım burada .


Güncellenen veriyi en üste taşımak istersem bunu nasıl yapacağım
Choy

@Choy, verileri güncelledikten sonra onu 0 dizinine taşıyabilirsiniz. Bu öğenin
Suragch

11

Değiştirilen metni model veri listenize ekleyin

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

10

Bununla nasıl başa çıkacağım konusunda bir fikrim olduğunu düşünüyorum. Güncelleme, tam konumunda silme ve değiştirme ile aynıdır. Bu yüzden önce aşağıdaki kodu kullanarak öğeyi o konumdan kaldırıyorum:

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

ve sonra öğeyi aşağıda gösterildiği gibi belirli bir konuma eklerim:

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

Şimdi bunu uygulamaya çalışıyorum. İşim bittiğinde size bir geri bildirim verirdim!


2
Fazladan bir adım atıyorsun. Sadece pozisyondaki elemanı değiştirin ve öğeyi notifyItemChanged (position) çağırın;
toshkinl

@toshkinl Verilerin JSONObject'ten geldiğini nasıl anlarsınız? pozisyonsuz mu?
olajide

7

Bu sorunu, değiştirilmesi gereken öğenin konumunu ve ardından adaptör çağrısında yakalayarak çözmeliyim.

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

, bu, bu belirli konumda bu belirli öğe için onBindViewHolder'ı (ViewHolder tutucu, int konumu) çağırır.


2

Aşağıdaki çözüm benim için çalıştı:

Bir RecyclerView öğesinde, kullanıcı bir düğmeye tıklar ancak TextView gibi başka bir görünüm, bağdaştırıcıya doğrudan bildirimde bulunmadan güncellenir:

NotifyDataSetChanged () yöntemini kullanmadan bunun için iyi bir çözüm buldum, bu yöntem tüm recyclerView verilerini yeniden yükler, böylece öğe içinde görüntü veya videonuz varsa, yeniden yüklenecek ve kullanıcı deneyimi iyi olmayacaktır:

Aşağıda, +1 ekledikten sonra benzer sayım güncellemesini göstermek için bir ImageView benzeri simgeye tıklamanın ve yalnızca tek bir TextView güncellemesinin (aynı öğe ile aynı şekilde daha fazla görünüm güncellenebilir) bir örneği verilmiştir:

// 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

Benim için kişisel olarak işe yarayan bir yol, öğelerindeki değişikliklerle başa çıkmak için recyclerview'un adaptör yöntemlerini kullanmaktır.

Buna benzer bir şekilde gider, özel geri dönüştürücünüzün görünümünde şuna benzer bir yöntem oluşturun:

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

0

Adaptör sınıfınızda, onBindViewHolder yönteminde, ViewHolder'ı aşağıdaki kodda olduğu gibi setIsRecyclable (false) olarak ayarlayın.

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

    // Then your other codes
}

0

sadece kaydetme tıklandığında uyarı iletişim kutusuna aşağıdaki kodu eklemeniz gerekir

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

0

Sorun, RecyclerView.Adatpereleman indeksini döndüren herhangi bir yöntem sağlamıyor

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

Çözümüm, (öğe, konum) s için bir harita örneği oluşturmaktır.

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
}
  • eleman türü (burada sınıf Friend) uygulamalıdır hashCode()ve equals()hashmap'te anahtar olduğu için.

bir öğe değiştiğinde,

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

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

  }

Yardımcı bir yöntem tanımlamak iyidir

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

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

Harita örneği ( Map<Friend, Integer> posMap) gerekli değildir. Harita kullanılmıyorsa, liste boyunca döngü yapmak bir öğenin konumunu bulabilir.


-1

Bu aynı zamanda benim son sorunum. Burada benim çözümüm RecyclerView için veri modeli ve adaptör kullanıyorum

 /*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

bir nesne oluşturuyorsanız ve adaptörünüzde kullandığınız listeye ekliyorsanız, adaptördeki listenizin bir öğesini değiştirdiğinizde diğer tüm öğeleriniz de değişir, başka bir deyişle tamamen referanslarla ilgilidir ve listeniz değişmez o tek nesnenin ayrı kopyalarını tutun.


-5

RecyclerView adaptörünüzde, bir ArrayList ve ayrıca ArrayList'e addItemsToList(items)liste öğeleri eklemek için bir yönteme sahip olmalısınız . Daha sonra adapter.addItemsToList(items)dinamik olarak arayarak liste öğeleri ekleyebilirsiniz . Tüm liste öğeleriniz ArrayList'e eklendikten sonra adapter.notifyDataSetChanged()listenizi görüntülemek için arayabilirsiniz .

notifyDataSetChangedRecyclerView için adaptördeki kullanabilirsiniz


veriler için, bu herhangi bir sorun olmadan bu Listedeki özel -existing- öğeyi güncellenmesinde sorunumu çalışır evet ben ArrayList var
Elgendy

güncellenen öğenin konumuna sahip olmanız gerekir, ardından yeni öğeyi mList.add (konum) .setName ("yeni ad") gibi ilgili konumuna yerleştirmeniz gerekir; daha sonra mAdapter.notifyDataSetChanged () öğesini kullanın;
Nooruddin Lakhani

4
Bu cevap, tek bir öğeyi güncelleme isteğini görmezden geliyor. NotifyDataSetChanged () çağrısı yalnızca tüm veri kümesi değiştiğinde yapılmalıdır.
Mark McClelland
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.