8

This is the project Sto tentando di eseguire. Qui è il mio codice per l'onBindViewHolder dalla classe RecyclerView.AdapterRecyclerView ambiguos setVisibility function, facendo clic su una vista interessa più viste

@Override 
    public void onBindViewHolder(ViewHolder holder, final int position) { 

     TextView title = (TextView) holder.view.findViewById(R.id.title); 
     final TextView desc = (TextView) holder.view.findViewById(R.id.desc); 
     final ImageView imageView = (ImageView) holder.view.findViewById(R.id.imageView); 

     title.setText(pojos.get(position).getTitle()); 
     desc.setText(pojos.get(position).getDesc()); 

     imageView.setImageResource(pojos.get(position).getImage()); 

     imageView.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       desc.setText("clicked"); 
       desc.setBackgroundColor(Color.BLUE); 
       imageView.setImageResource(R.drawable.heart_red); 
      } 
     }); 

    } 

L'elenco carichi bene, il problema si verifica quando onclicklistener del ImageView si chiama.

desc.setText("clicked"); 

La riga in alto consente di modificare la voce di elenco su cui è stato fatto clic. ma

desc.setBackgroundColor(Color.BLUE); 

quando questa riga viene eseguita, la modifica si riflette in più elementi nell'elenco. Cosa sta andando storto? Nelle immagini mostrate di seguito, ho fatto clic sull'elemento 0, il testo cambia in "clic" e il colore è impostato. Ma quando scorro verso il basso, l'elemento 12 è stato anch'esso influenzato dal mio clic sull'elemento 0. Solo il cambiamento del colore di sfondo ha riflesso, non il cambio di testo. Come lo fermo?

enter image description here

enter image description here

Ho cercato di risolvere questo per un lungo periodo di tempo, gentilmente scaricare il progetto e provare a eseguire il codice per capire cosa esattamente dire, se la mia domanda non è chiara.

risposta

11

Questo accade perché il punto di vista ottengono riciclato e riutilizzato.

Così, quando la vista viene riciclata, mantiene le proprietà della "vecchia" vista se non le si cambia di nuovo. Quindi, quando scorri verso il basso fino al numero 12, la vista che teneva il numero 1 viene riciclata (poiché non può più essere vista sullo schermo) e viene utilizzata per creare il numero 12. Ecco perché il colore blu è sul numero 12.

Quando l'elemento viene, ad esempio, fatto clic, è necessario salvare un valore "cliccato" nell'oggetto POJO. Quindi, quando l'elemento viene disegnato, controlla quel valore e imposta il colore dell'immagine/dello sfondo corretto in base a quel valore.

ho fatto questo nel seguente codice, e quindi dovrebbe darvi una vaga idea di cosa fare:

@Override 
public void onBindViewHolder(ViewHolder holder, final int position) { 
    TextView title = (TextView) holder.view.findViewById(R.id.title); 
    final TextView desc = (TextView) holder.view.findViewById(R.id.desc); 
    final ImageView imageView = (ImageView) holder.view.findViewById(R.id.imageView); 

    final MyPojo pojo = pojos.get(position); 

    title.setText(pojo.getTitle()); 
    if(!pojo.clicked) { 
     desc.setText(pojo.getDesc()); 
     imageView.setImageResource(pojo.getImage()); 
     desc.setBackgroundColor(Color.argb(0,0,0,0)); 
    } else { 
     desc.setText("clicked"); 
     desc.setBackgroundColor(Color.BLUE); 
     imageView.setImageResource(R.drawable.heart_red); 
    } 

    imageView.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      pojo.clicked = true; 
      desc.setText("clicked"); 
      desc.setBackgroundColor(Color.BLUE); 
      imageView.setImageResource(R.drawable.heart_red); 
     } 
    }); 
} 

e ho aggiunto una "cliccato" boolean alla classe MyPojo.

public class MyPojo { 

    String title; 
    String desc; 
    int image; 
    boolean clicked; 
} 
+0

Capisco la vostra soluzione. Ma perché setText e setBackgroundColor funzionano in modo diverso? perché il setText funziona esattamente come lo vogliamo fuori dagli schemi? – 55597

+0

Non funziona dinamicamente, sry :) – delive

+1

Amen a quello! Grazie per l'ottima spiegazione :) – Cbr

0

Ho avuto un problema simile, (ho avuto un cambio di numero su più elementi di lista invece di uno solo). Presumo che sia a causa di come funziona una vista di riciclo, sono stato in grado di risolverlo impostando tutto ciò che stavo progettando di modificare in quello che voglio essere il default.

IE: se si desidera modificare lo sfondo in blu, quando si carica l'elenco impostare quelli che non devono essere di colore blu a grigio (o quello che si desidera che il valore predefinito sia).

ecco:

ViewHolder vh = new ViewHolder(v); 
return vh; 

si desidera specificare le impostazioni di default

-1

qui tenta di utilizzare questo adattatore:

public class myAdapter extends RecyclerView.Adapter<CopyOfConversationAdapter.ViewHolder> { 
private ArrayList<conversationItem> pojos; 
// inner class to hold a reference to each item of RecyclerView 
public static class ViewHolder extends RecyclerView.ViewHolder { 

    TextView title; 
    TextView desc; 
    ImageView imageView; 


    public ViewHolder(View itemLayoutView) { 
     super(itemLayoutView); 
     title= (TextView) itemLayoutView.findViewById(R.id.title); 
     desc= (TextView) itemLayoutView.findViewById(R.id.desc); 
     imageView= (ImageView) itemLayoutView.findViewById(R.id.imageView); 
    } 
} 

// Return the size of your itemsData (invoked by the layout manager) 
@Override 
public int getItemCount() { 
    return pojos.size(); 
} 

public CopyOfConversationAdapter(Pojos[] pojos) { 
    this.pojos = new ArrayList<conversationItem>(); 
    this.pojos.addAll(Arrays.asList(Items)); 
} 
// Create new views (invoked by the layout manager) 
@Override 
public CopyOfConversationAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    // create a new view 
    View itemLayoutView; 
     itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.comments_item_layout_, null); 

    ViewHolder viewHolder = new ViewHolder(itemLayoutView); 
    return viewHolder; 
} 

// Replace the contents of a view (invoked by the layout manager) 
@Override 
public void onBindViewHolder(ViewHolder viewHolder, final int position) { 

    // - get data from your itemsData at this position 
    // - replace the contents of the view with that itemsData 

    viewHolder.title.setText(pojos.get(position).getSender()); 
    viewHolder.desc.setText(pojos.get(position).getSnippet()); 
    viewHolder.imageView.setText(pojos.get(position).getIcon()); 
    viewHolder.imageView.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      // TODO Auto-generated method stub 
      desc.setText("clicked"); 
       desc.setBackgroundColor(Color.BLUE); 
       imageView.setImageResource(R.drawable.heart_red); 
     } 
    }); 

} 

}

2

Sembra che si dispone di una confusione sull'uso RecyclerView chiamando a findViewById in onBindViewHolder. Queste costose ricerche dovrebbero accadere in onCreateViewHolder, dove si cercano tutte le viste e si salvano i riferimenti al titolare della vista personalizzato. Sono andato avanti a guardato il codice in github pronti contro termine e proporre le seguenti modifiche:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { 

private ArrayList<MyPojo> pojos; 

// Provide a reference to the views for each data item 
// Complex data items may need more than one view per item, and 
// you provide access to all the views for a data item in a view holder 
public static class ViewHolder extends RecyclerView.ViewHolder { 
    // each data item is just a string in this case 
    public TextView title; 
    public TextView desc; 
    public ImageView imageView; 

    public ViewHolder(View v) { 
     super(v); 

     // all expensive findViewById lookups happen in ViewHolder constructor, 
     // which is called only when onCreateViewHolder is called 
     this.title = (TextView) v.findViewById(R.id.title); 
     this.desc = (TextView) v.findViewById(R.id.desc); 
     this.imageView = (ImageView) v.findViewById(R.id.imageView); 
    } 
} 

// Provide a suitable constructor (depends on the kind of dataset) 
public MyAdapter(ArrayList<MyPojo> pojos) { 
    this.pojos = pojos; 
} 

// Create new views (invoked by the layout manager) 
@Override 
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, 
               int viewType) { 
    // create a new view 
    View v = LayoutInflater.from(parent.getContext()) 
      .inflate(R.layout.row, parent, false); 
    // set the view's size, margins, paddings and layout parameters 
    ViewHolder vh = new ViewHolder(v); 
    return vh; 
} 

// Replace the contents of a view (invoked by the layout manager) 
@Override 
public void onBindViewHolder(ViewHolder holder, final int position) { 
    // this callback will be constantly called during scrolling 
    // therefore, to make it smooth, we should not make any expensive operations here 
    // - get element from your dataset at this position 
    // - replace the contents of the view with that element 
    holder.title.setText(pojos.get(position).getTitle()); 
    holder.desc.setText(pojos.get(position).getDesc()); 
    holder.imageView.setImageResource(pojos.get(position).getImage()); 

    // you'll need to implement this function based on the way you decide to save clicked state for each clicked view 
    if(isClickedState(position)) { 
      holder.imageView.setImageResource(R.drawable.heart_red); 
    } else { 
      // provide some default background 
      holder.imageView.setImageResource(R.drawable.default); 
    } 

    holder.imageView.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      // you'll need to implement this function to save clicked position 
      saveClickForPosition(position) 
      imageView.setImageResource(R.drawable.heart_red); 
     } 
    }); 
} 

// Return the size of your dataset (invoked by the layout manager) 
@Override 
public int getItemCount() { 
    return pojos.size(); 
} 
} 

Questo dovrebbe essere il punto di partenza per il debug come seguendo questo modello garantirà il corretto riciclo.

Come viene anche menzionato in un'altra risposta, è necessario ricordare lo stato cliccato per ciascun elemento e mantenere questo stato nell'oggetto MyPojo o altrove dovrebbe essere relativamente facile da eseguire.

6

Basta aggiungere un metodo nella classe di adattatori dopo il metodo GetItemCount

@Override 
    public int getItemViewType(int position) { 
     return position; 
    } 

che possa risolvere il problema

+1

Questo letteralmente interromperà anche l'intero punto di avere un RecyclerView. Questo disabilita TUTTO il riutilizzo della vista. In pratica stai dicendo a RecyclerView che ogni singolo elemento nell'elenco dovrebbe avere una propria cella di visualizzazione che non può mai essere riciclata. Quindi se carichi le immagini in quelle celle RecyclerView, l'utilizzo della memoria andrà al di là del tetto. – Moonbloom