Drawable Mutations

来源:互联网 发布:用sql创建数据库 编辑:程序博客网 时间:2024/06/05 06:13

Android 的Drawable在应用程序开发中使用的非常广泛.我们可以把Drawable看作一个可插拔的绘图容器,这个容器通常与一个View相关联.例如,一个BitmapDrawable 通常被用来显示图片,一个 ShapeDrawable通常被用来绘制图形或渐变,你可以混合使用他们,用来复杂的渲染.

Drawable可以使你非常容易地定制化渲染那些widget而不需要继承它们,在android核心框架层,使用了约700多个Drawable.当他们从资源中被加载进来的时候android对它们进行了优化.例如,每次创建一个Button时, 系统会从框架层的资源里面 ( android.R.drawable.btn_default )加载一个新的 drawable.这就意味着APP层所使用的所有的Button都使用着各不相同的drawable实例来作为自己的背景.尽管如此,所有的drawable共享着一个共同的状态,称做 "constant state." 这个状态变量的内容随着你使用的drawable的类型的变化而变化,但通常情况下,它包含了资源文件中所能够定义的所有属性.例如,在一个button中constant state 包含了一个bitmap图象.在这种情况下,所有应用程序中的button共享着同一份bitmap,这样节约了内存.

这样做虽然节约了内存,但是也带来了一些坏处:当我们需要修改drawable的属性时,修改其中一个会影响到其他的.以下是一个例子:

Book book = ...;
TextView listItem = ...;

listItem
.setText(book.getTitle());

Drawable star = context.getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
  star
.setAlpha(255); // opaque
} else {
  star
.setAlpha(70); // translucent
}

在一个listview中放置了很多item,每个item中有一个imageview和一段文字,我们想将喜爱的书对应的item中的imageview置为不透明状态,其他的置为透明状态.

不幸的是,结果出人意料:所有的imageview都处于透明状态.这样的结果可以用constant state来解释.尽管我们为每个item获取到了一个新的drawable 实例,但他们仍然共享着同样一份constant state,在BitmapDrawable中,透明度是constant state的一部分,所以,修改其中一个的透明度会影响其它所有的透明度.

Android 1.5 及以上的版本提供了一个方法mutate() 用来解决上述问题.当你调用drawable的这个方法时,constant state被拷贝一份,这样就你修改当前的drawable就不会影响到其他的drawable了.需要注意的是,这些drawable仍然共享同一份bitmap.以下是修改后的代码:

Drawable star = context.getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
  star
.mutate().setAlpha(255); // opaque
} else {
  star
. mutate().setAlpha(70); // translucent
}

这样就可以达到我们期望的结果