问题回顾
在上一篇博客 Android 进阶学习(二十四) Android 中给View 添加Drawable的思考 的结尾处 ,我说出了一个问题,那就是我自己写的drawable 缓存,缓存的是drawable 本身,这就使得不同的View 在使用相同的drawable时,drawable 不适配的情况,比如 RecyclerView 的item 是一个 水平自动填充的item , 如果上一个使用这个drawable 的item 宽度比当前这个item的宽度宽,就会导致当前这个item 的背景drawable 的宽度超过了item的宽度,出现不适配的情况,那么这种情况 源码是如何解决的呢,
@Nullable
Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,
int density, @Nullable Resources.Theme theme)
throws NotFoundException {
...省略部分代码
if (!mPreloading && useCache) {
这里就是获取缓存的drawable
final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
if (cachedDrawable != null) {
cachedDrawable.setChangingConfigurations(value.changingConfigurations);
return cachedDrawable;
}
}
...省略部分代
}
}
class DrawableCache extends ThemedResourceCache {
@UnsupportedAppUsage
public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
final Drawable.ConstantState entry = get(key, theme);
if (entry != null) {
每次都是利用 Drawable.ConstantState 重新创建一个drawable
return entry.newDrawable(resources, theme);
}
return null;
}
}
从源码这里我们可以看到,即使使用的是同样的drawable.xml 文件,每个view 的drawable 都是单独创建的,只不过这个模板只创建了一次,所以我们的缓存也需要缓存 Drawable.ConstantState ,每次获取后,重新创建一个新的Drawable
Drawable 组件化
我们app 在探究组件化的过程中关于drawable 的问题也遇到了不少, 由于组件化开发的过程是先有的app,我们再对app进行组件化拆分,在组件化的初期,很多资源文件都是到处copy 的,虽然我们给组件添加了 resourcePrefix 这个属性,为每个组件的xml 资源命名做了限制,还是造成了不少打最终包成功后样式对不上的问题,而且随着项目越来越大,新写一个drawable 所耗费的时间,比找到一个相同属性的drawable 的xml文件还要快一点,这样就造成了恶性循环,大家就不停的创建新的drawable.xml 文件,找到相同属性的就更难了...
伴随着这样的思考,能不能找到一个摆脱xml来设置背景drawable 的方法就这样诞生了,但是这个过程也遇到了好几个问题
1.也就是上面我们所说的 drawable 缓存的问题,通过缓存 Drawable.ConstantState 每次获取都重新创建drawable 这个问题已经解决了
2.我在最开始的时候为整个项目重新定义了一套 DrawableView ,比如 DrawableTextView , DrawableLinearLayout , DrawableRelativeLayout 等等, 在为每个View 添加属性的时候,就产生了一个问题,那就是
每一个View 在使用 xml 添加drawable 属性的时候,他们属性命名是不同的,LinearLayout 的属性就是 app:ll_zhome_color=""
RelativeLayout 的属性就是 app:rl_zhome_color="",这样就导致了不了解这个机制的人,如果只是copy属性,就会导致使用不了这个问题,那么能不能像 ConstraintLayout 一样, 所有view 的属性名都一致,并且android studio 还会自动提示出属性的名称呢,
这个问题的解决方案自己想一下其实也特别简单,那就是事先将属性声明出来,在自定义View 的 declare-styleable 引用这个属性就可以了,举个栗子
先把这个 属性在 resources 标签下声明出来
这样就可以了,虽然在获取属性的时候是根据不同的View 来获取的,但是在编写 layout.xml 的过程中, 属性的命名是一致的,
插个图
下面就是我们在使用过程中经常遇到的属性,我把它们每个属性都标注了出来,方便使用的人来查看并使用相关的属性,
到了这里整个过程就告一段落了,这个一套drawable 在我们的组件里面已经试用了很长一段时间了,并没有出现什么问题,下面我方一下Github 地址 TsmBottomSheetDialog,这里就能找到相关代码