Reputation: 1726
I have a RecyclerView
with an icon in each row. The icon should be colored dynamically, so I use a white icon and apply a color filter when binding the view. Oddly enough, I end up with a lot of discrepancies in the resulting view.
In this example I'm attempting to make every third row red and the rest green (note #18):
Below is the adapter. As you can see, I'm applying the altered icon to the ImageView
every time I rebind the holder, presumably leaving no room for the old recycled image.
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>
What gives?
Thanks.
Upvotes: 3
Views: 2156
Reputation: 8231
Having read your comments, I'm not sure whether this is suitable to your requirements. However, I was able to replicate the expected behaviour by setting the "brightness" drawable with the android:src
element in the layout file, then applying the filter to the ImageView
(rather than the icon):
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:
It also works if you set the icon dynamically, but apply the filter to the 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);
}
}
Upvotes: 2
Reputation: 24211
Try using this code segment in your 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);
}
Upvotes: 0