用于预棒棒糖的RecyclerView中的可绘制着色

时间:2016-02-05 12:59:38

标签: android android-drawable android-recyclerview

我正在尝试使用我的RecyclerView中的以下代码进行可绘制着色

Drawable likeDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_thumb_up);
Drawable likeWrappedDrawable = DrawableCompat.wrap(likeDrawable);
DrawableCompat.setTint(likeWrappedDrawable,ContextCompat.getColor(getActivity(), android.R.color.white));
holder.ivLike.setImageDrawable(likeWrappedDrawable);

现在所有这些都在RecyclerView适配器的onBindViewHolder

中完成

我根据该列表项的状态在三种颜色之间更改此色调。这对于Lolipop及以上版本都很好,但在此版本之下,列表项的颜色是不可预测的。有时候它会显示正确的颜色,但在刷新列表时有时它会变成其他颜色。

在这种特殊情况下,任何我在这里做错了或者棒棒糖前的着色东西仍然无法使用?

更新 包括我onBindViewHolder

中的代码
@Override
        public void onBindViewHolder(ViewHolder holder, int position) {
...

            Drawable likeDrawable =
                    ContextCompat.getDrawable(getActivity(), R.drawable.ic_thumb_up);


            Drawable likeWrappedDrawable = DrawableCompat.wrap(likeDrawable);


                holder.tvLikeCount.setTextColor(ResUtil.getColor(R.color.light_font,
                        getActivity()));

                DrawableCompat.setTint(likeWrappedDrawable,
                        ContextCompat.getColor(getActivity(), android.R.color.white));

                if (tweetModel.isFavorited()) {
                DrawableCompat.setTint(likeWrappedDrawable,
                        ContextCompat.getColor(getActivity(), android.R.color.holo_blue_light));
            }



            holder.ivLike.setImageDrawable(likeWrappedDrawable);

        }

2 个答案:

答案 0 :(得分:4)

在调用setTint()

之前调用Drawable上的mutate()
Drawable likeDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_thumb_up).mutate();

默认情况下,从同一资源加载的所有drawables实例共享一个公共状态;如果修改一个实例的状态,则所有其他实例将收到相同的修改。 http://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate()

答案 1 :(得分:0)

TL;DR。如果您担心效率,请使用 TintedIconCache,您可以从 this gist 获取单个类。

TintedIconCache cache = TintedIconCache.getInstance();
Drawable myTintedDrawable = cache.fetchTintedIcon(context, R.drawable.icon_01, R.color.color_01));

需要做的不仅仅是.mutate()

正如@Vladimir 所说,您必须调用 drawable.mutate() 才能获得隔离状态,否则对您的可绘制属性所做的任何更改都将反映在共享相同状态的所有其他可绘制对象上。

这种行为实际上是有充分理由的,其中之一是内存效率,并且在某些情况下您希望保持这种效率。

例如,您可能有一个 RecyclerView ,其中的项目使用相同的可绘制对象,但根据某些属性(例如成功、失败、警告、信息等)为每个项目着色不同。如果你在这种情况下,为每个项目改变你的 drawable 并不是最好的解决方案。您可以考虑使用所有可能的色调创建所有可能的可绘制对象,但您可能会创建无用的一次。如果您是这种情况,我会为您提供保障!

输入 TintedIconCache

更好的解决方案是拥有某种可绘制缓存,其中每个唯一着色的可绘制仅在需要时创建,然后有效地缓存以用于后续需求,直到您不再需要它或系统想要收回占用的内存。

>

我已经在 TintedIconCache 中实现了这一点。使用起来很简单:

// Get an instance
TintedIconCache cache = TintedIconCache.getInstance();

// Will be fetched from the resources
Drawable backIcon = cache.fetchTintedIcon(context, R.drawable.icon, R.color.black));

// Will be fetched from the resources as well
Drawable bleuIcon = cache.fetchTintedIcon(context, R.drawable.icon, R.color.bleu));
   
// Will be fetched from the cache!!!
Drawable backIconTwo = cache.fetchTintedIcon(context, R.drawable.icon, R.color.back));

考虑查看 gist 以了解其内部工作原理。