(翻译) Android SDK文档之Drawable Mutations
原文来自Android SDK文档中的 resources/articles/drawable-mutations.html
Android的drawables非常便于构建应用。Drawable是一个可插拨的绘制容器(drawing container), 通常与一个View关联。 比如, BitmapDrawable用于显示图片, ShapeDrawable用于绘制图形和渐变, 等等。 还可以组合使用,创建更复杂的渲染效果。
Drawables允许不必继承Widget就可以方便地定制Widget的渲染效果。事实上, 它们是如此方便易用,多数自带的Android应用和Widget是通过使用Drawables来构建的。 Android核心框架使用了大约700个Drawables。 由于Drawables的系统中大量使用, Android优化过其加载过程。 比如, 每次当你创建一个Button, 一个新的Drawable将从框架资源文件中(android.R.drawable.btn_default)加载进来。 这意味着所有应用中所有的button使用不同的Drawable实例作为它们的背景。 但是所有这些Drawables共享相同的状态, 即Constant State。 这个状态中的内容因使用的Drawable类型而变化,但通常都包含所有可用的资源属性。 以button为例, Constant State包含一个Bitmap Image。 这样,所有应用中的所有Button都共享相同的Bitmap, 可以节省大量内存。
下图展示当把同一个Image资源作为两个不同的View的背景时哪些实体将被创建。 正如你所见, 两个Drawable被创建,但他们共享同一个Constant State, 即同一个Bitmap
虽然共享Constant State这个特性有利于减少内存的使用, 但当你需要修改Drawable的属性时可能产生问题。 考虑一个应用, 它有一个Book列表。 每个Book书名旁边有一个星形, 当用户标记当前Book为喜欢时这个星形完全不透明, 而未标记为喜欢时这个星形为半透明。 为实现这个显示效果, list adapter中的getView()方法可以这样写:
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 }很不幸, 以上代码将产生奇怪的结果:所有的星形都成了半透明。如下图所示:
这个结果也说明了Constant State的特点。 尽管我们为每个Item生成了一个新的Drawable实例, Constant State仍然是相同的。 对BitmapDrawable而言, 透明度也是Constant State的一部分。因此, 改变一个Drawable实例的透明度, 同时也会影响其他Drawable实例的透明度。 更糟糕的是, 这个问题在Android 1.0和Android 1.1上不容易修复。
Android 1.5及以上版本提供了一个简单的办法来解决这个问题:新添加的mutate()方法。当你在某个Drawable上调用mutate()方法时, 将复制该Drawable的Constant State, 并允许修改该复制结果的属性且不会对其他Drawable生成影响。 注意, 就算复制了Drawable, Drawable仍然共享Bitmap。 下图显示了在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实例 。 修改后的代码结果是正确的。
(另外附上自己根据这篇文档写的一个例子, 验证下mutate()的用法)
代码:
public class ConstantStateActivity extends ListActivity { private ListAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAdapter = new MyListAdapter(this, R.layout.my_adatper, R.id.textView1, Arrays.asList("and-aa", "iphone-b")); getListView().setAdapter(mAdapter); } static class MyListAdapter extends ArrayAdapter<String> { private int mRes; private List<String> mData; public MyListAdapter(Context context, int resource, int textViewResourceId, List<String> objects) { super(context, resource, textViewResourceId, objects); this.mRes = resource; this.mData = objects; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (null == view) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(LAYOUT_INFLATER_SERVICE); view = inflater.inflate(mRes, parent, false); ImageView icon = (ImageView) view.findViewById(R.id.imageView1); MyLog.i(icon + ""); if (mData.get(position).startsWith("and")) { icon.getDrawable().setAlpha(0); // icon.getDrawable().mutate().setAlpha(0); } } return view; } } }布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_vertical"> <ImageView android:layout_height="wrap_content" android:src="@drawable/icon" android:layout_width="wrap_content" android:id="@+id/imageView1"></ImageView> <TextView android:text="TextView" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView> </LinearLayout>不调用mutate()时截图如下(ImageView都变成透明的了, 所以看不见)
调用mutate()方法时截图如下(一个ImageView透明, 另一个不透明, 正确结果!)
相关推荐
huavhuahua 2020-09-05
magic00 2020-08-03
风萧萧梦潇 2020-06-14
jiejie 2020-06-02
pengjin 2020-05-14
kururunga 2020-05-07
fengyeezju 2020-04-26
PrisonJoker 2020-04-16
fengyeezju 2020-04-07
hqulyc 2020-03-05
fengyeezju 2020-02-09
fengyeezju 2020-02-02
Urchindong 2020-01-21
fengyeezju 2020-01-11
绿豆饼 2020-01-05
csdnuuu 2019-12-27