2016-01-06 2 views
3

J'ai un RecyclerView avec une icône dans chaque rangée. L'icône doit être colorée dynamiquement, j'utilise donc une icône blanche et j'applique un filtre de couleur lors de la liaison de la vue. Assez curieusement, je me retrouve avec beaucoup de divergences dans la vue qui en résulte.Recyclage d'image incorrect dans RecyclerView

Dans cet exemple, je suis tenté de faire tous les trois rangs rouge et le vert reste (note n ° 18):

enter image description here

est Ci-dessous l'adaptateur. Comme vous pouvez le voir, j'applique l'icône altérée au ImageView chaque fois que je rebondis le support, sans doute ne laissant aucune place pour l'ancienne image recyclée.

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

    private final Context context; 

    public TestAdapter(Context context) { 
     this.context = context; 
    } 

    @Override 
    public TestAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false); 
     return new ViewHolder(itemView); 
    } 

    @Override 
    public void onBindViewHolder(TestAdapter.ViewHolder holder, int position) { 
     holder.bindItem(position); 
    } 

    @Override 
    public int getItemCount() { 
     return 200; 
    } 

    public class ViewHolder extends RecyclerView.ViewHolder { 

     private final ImageView image; 
     private final TextView text; 

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

      image = (ImageView) itemView.findViewById(R.id.image); 
      text = (TextView) itemView.findViewById(R.id.text); 
     } 

     public void bindItem(int position) { 
      // pick color depending on the position 
      final int color = ContextCompat.getColor(context, 
        position%3 == 0 ? android.R.color.holo_red_light : android.R.color.holo_green_light 
      ); 

      // set text content and color 
      text.setText("#" + position); 
      text.setTextColor(color); 

      // create icon from the resource and set filter 
      final Drawable icon = ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_brightness, null); 
      icon.setColorFilter(color, PorterDuff.Mode.MULTIPLY); 

      image.setImageDrawable(icon); 
     } 
    } 

} 

item_layout.xml:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:orientation="horizontal" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <ImageView 
     android:id="@+id/image" 
     android:layout_width="18dp" 
     android:layout_height="wrap_content" 
     android:scaleType="fitStart" 
     android:adjustViewBounds="true" /> 

    <TextView 
     android:id="@+id/text" 
     android:textSize="18sp" 
     android:textColor="@android:color/black" 
     android:layout_marginLeft="48dp" 
     android:layout_marginStart="48dp" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:gravity="center_vertical" 
     tools:text="text" /> 

</LinearLayout> 

Qu'est-ce qui se passe?

Merci.

+0

Si vous voulez avoir différents types de vues, Au lieu de choisir la position, pensez à surcharger la méthode 'getItemViewType'. –

+0

Le problème est que dans le projet réel la couleur peut être arbitraire, elle vient d'un serveur. – SqueezyMo

+0

C'est intéressant. Avez-vous testé cela avec différentes icônes, plutôt qu'avec le filtre, pour voir si vous obtenez toujours les mêmes résultats? – PPartisan

Répondre

2

Après avoir lu vos commentaires, je ne suis pas sûr que ce soit adapté à vos besoins. Cependant, je suis en mesure de reproduire le comportement attendu en réglant le drawable « luminosité » avec l'élément android:src dans le fichier de mise en page, puis en appliquant le filtre à la ImageView (plutôt que l'icône):

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

    public RecyclerViewAdapter() { 
    } 

    @Override 
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { 
     View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.rv_row, viewGroup, false); 
     return new ViewHolder(v); 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder viewHolder, int i) { 
     viewHolder.bindItem(i); 
    } 

    @Override 
    public int getItemCount() { 
     return 200; 
    } 

    public static class ViewHolder extends RecyclerView.ViewHolder { 

     private final ImageView image; 
     private final TextView text; 

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

      image = (ImageView) itemView.findViewById(R.id.image); 
      text = (TextView) itemView.findViewById(R.id.text); 
     } 

     public void bindItem(int position) { 

      final int color = ContextCompat.getColor(itemView.getContext(), 
        position % 3 == 0 ? android.R.color.holo_red_light : android.R.color.holo_green_light 
      ); 

      text.setText("#" + position); 
      text.setTextColor(color); 

      image.setColorFilter(color, PorterDuff.Mode.MULTIPLY); 
     } 
    } 
} 

EDIT:

Il fonctionne également si vous définissez l'icône dynamique, mais d'appliquer le filtre à la ImageView:

public static class ViewHolder extends RecyclerView.ViewHolder { 

    private final ImageView image; 
    private final TextView text; 

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

     image = (ImageView) itemView.findViewById(R.id.image); 
     text = (TextView) itemView.findViewById(R.id.text); 
    } 

    public void bindItem(int position) { 

     final int color = ContextCompat.getColor(itemView.getContext(), 
       position % 3 == 0 ? android.R.color.holo_red_light : android.R.color.holo_green_light 
     ); 

     text.setText("#" + position); 
     text.setTextColor(color); 

     Drawable icon = getIcon(); 

     image.setImageDrawable(icon); 
     image.setColorFilter(color, PorterDuff.Mode.MULTIPLY); 
    } 

    @TargetApi(Build.VERSION_CODES.LOLLIPOP) 
    private Drawable getIcon() { 
     return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
       ? image.getContext().getResources().getDrawable(R.drawable.ic_brightness_1_white_24dp, null) 
       : image.getContext().getResources().getDrawable(R.drawable.ic_brightness_1_white_24dp); 
    } 
} 
+1

Merci, ça marche parfaitement! Pendant ce temps, j'ai commencé à lire le code source de 'BitmapDrawable' et suis tombé sur un commentaire vraiment utile: " Un bitmapDrawable mutable partage toujours son bitmap avec tout autre dessin qui provient de la même ressource ". Donc, une autre chose qui marche s'appelle 'icon = icon.mutate()' avant de définir 'setColorFilter()' mais j'aime beaucoup plus votre solution. – SqueezyMo

0

Essayez d'utiliser ce segment de code dans votre Bindview

int color; 
if(position%3 == 0){ 
    color = android.R.color.holo_red_light; 
    text.setText("#" + position); 
    text.setTextColor(color); 
    Drawable icon = ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_brightness, null); 
    icon.setColorFilter(color, PorterDuff.Mode.MULTIPLY); 
    image.setImageDrawable(icon); 

} else{ 
    color = android.R.color.holo_red_light; 
    text.setText("#" + position); 
    text.setTextColor(color); 
    Drawable icon = ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_brightness, null); 
    icon.setColorFilter(color, PorterDuff.Mode.MULTIPLY); 
    image.setImageDrawable(icon); 
} 
+2

Merci, mais c'est à peu près la même logique. Malheureusement, le problème demeure. – SqueezyMo

+0

Avez-vous essayé cela? –

+0

Oui, je l'ai essayé. – SqueezyMo