Android(安卓)SDK文档之Drawable Mutations
16lz
2022-05-13
原文来自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;@Overrideprotected 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;}@Overridepublic 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透明, 另一个不透明, 正确结果!)
更多相关文章
- Android(安卓)中Preferences的使用!
- Android(安卓)- Android(安卓)Studio 自动(auto)添加import 语句
- android SharedPreferences 使用
- Android使用系统方法实现分享到QQ和微信!
- android后台运行服务,加验证
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerT
- 箭头函数的基础使用
- NPM 和webpack 的基础使用
- Python list sort方法的具体使用