Drawable Mutations--绘图变异

来源:互联网 发布:mac没有flash怎么办 编辑:程序博客网 时间:2024/05/20 14:41

原文连接:点击打开链接

        Android提供的Drawable对构建应用程序极为有用。Drawable是一个与View相关的可插入式绘图容器。如:BitmapDrawable用于图片显示,ShapeDrawable用来绘制蒙板和渐变图,等等。通过组合使用则可以创建更为复杂的渲染效果。

    Drawables允许用来方便的定制Widget,而毋需继承它。事实上,由于Drawables如此的方便,以至大量默认的Android应用程序和Widget都是用它构建的;Android的核心框架中,大约用了700个Drawables。由于Android系统中Drawables使用如此之广泛,因此,Android从资源中加载它们时也进行了优化。例如,每次创建一个Button时,一个新的Drawable就从框架资源文件(android.R.drawable.btn_default)中被加载。这就意味着:所有应用中的所有Buttons使用不同的Drawables实例作为它们的背景图案。但是,所有这些Drawables共享一个通用状态:“constant state(常态)”。状态内容根据所用drawable的类型而变,但通常包含了资源文件可定义的所有属性。

Button为例,常态时包含了一幅位图,这样的话,所有应用中的所有buttons共享这幅位图,节省了很多空间。

        下面的框图显示了当你将同一幅图指定给两个不同的View作背景时哪些实体被创建了。如你所见,两个drawables被创建了,但它们共享同一个常态和同一幅图:


这种状态共享特性在避免浪费内存的同时,也给修改drawable属性带来了问题。设想有一个用到图书列表的应用程序。每本书名旁边都有一颗星,当星标记为完全不透明时,表示喜爱;标记为半透明的时,表示不喜爱。为达到这个效果,你很可能在你的list adapter'sgetView()方法中这样写代码:

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}
不幸的是,这段代码会产生一个相当奇怪的结果:所有的drawables都具有同样的透明度:


这种结果就可以用“constant state”来解释了。尽管我们在每个列表项中都获得了一个新的drawable实例,但“constant state”和BitmapDrawable仍然是共享的,而透明度是“constant state”的一部分。因此,改变一个drawable实例的透明度,就会改变其它多有drawable实例的透明度。更糟糕的是,在Android早期版本1.0和1.1中解决此类问题是很难的。

      Android 1.5及其之后的版本通过提供一个新的方法:mutate(),就很容易的解决了这个问题。当你在drawable中使用该方法时,drawable的“constant state”被复制了,这样就允许你在不影响其它drawable属性的情况下修改你想要修改的drawable的任何属性。注意:即使对drawable进行了变异处理,位图仍然是共享的。下面这幅框图展示了drawable上使用mutate()方法后发生了哪些变化:


使用mutate( )修改前面的代码片段:

Drawable star = context.getResources().getDrawable(R.drawable.star);if (book.isFavorite()) {  star.mutate().setAlpha(255); // opaque} else {  star. mutate().setAlpha(70); // translucent}
为了方便,mutate( )返回的是drawable自身,这样可以进行链式的方法调用,而并未创建新的drawable实例。使用新的代码片段后,应用程序现在可以正常工作了:


博主注:所译内容,已经经过代码验证,情况确实如上所述。