Drawable文件夹主要用于存放应用程序中的可绘制图形对象资源,这些可绘制对象资源可以是:位图文件(BitmapDrawable),九宫格文件( NinePatchDrawable),图层列表(LayerDrawable),状态列表(StateListDrawable),级别列表(LevelListDrawable),转换可绘制对象(TransitionDrawable),插入可绘制对象,裁剪可绘制对象( ClipDrawable),缩放可绘制对象(ScaleDrawable),形状可绘制对象(ShapeDrawable)。
其中位图文件支持三种格式的位图文件:png(首选),jpg(可接受),gif(不建议)。在编译时的资源数据类型,指向 BitmapDrawable 的资源指针。
通常,图标在正常时一种颜色, 在点击时一种颜色。但是,在这种情况下,并不需要使用两张图片。
使用Tint:
/**
* @param context 上下文对象
* @param resId 图片资源
* @param colorId 颜色资源
* @return 着色后的Drawable
*/
public static Drawable getTintDrawable(Context context, @DrawableRes int resId, @ColorRes int colorId) {
Drawable drawable = AppCompatResources.getDrawable(context, resId);
ColorStateList colorStateList = ContextCompat.getColorStateList(context, colorId);
Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTintList(wrappedDrawable, colorStateList);
return wrappedDrawable;
}
颜色状态资源arrow_back.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorAccent" android:state_enabled="true" android:state_pressed="true"/>
<item android:color="@android:color/white" android:state_enabled="true"/>
selector>
设置着色后的drawable:
imageView.setImageDrawable(DrawableUtil.getTintDrawable(this, R.drawable.ic_arrow_back_white, R.color.arrow_back));
效果图下图所示:
注意:如果ImageView设置没有效果,需要添加:
imageView.setClickable(true);
原因是,当View是可点击的时候,在每一次点击中,它才会将状态改变为”pressed”。
有时,同一张图片,在不同的页面主题中显示不同的颜色。
使用Tint:
/**
* @param drawable 要着色的Drawable
* @param colorStateList 颜色状态列表
* @return 着色后的Drawable
*/
public static Drawable getTintDrawable(Drawable drawable, ColorStateList colorStateList) {
Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTintList(wrappedDrawable, colorStateList);
return wrappedDrawable;
}
imageView.setImageDrawable(DrawableUtil.getTintDrawable(ContextCompat.getDrawable(this, R.drawable.ic_arrow_back_white), ColorStateList.valueOf(Color.RED)));
效果图下图所示:
也可以使用Drawable的
setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode)方法:
/**
* @param srcDrawable 要着色的Drawable
* @param color 着色颜色
* @return 着色后的Drawable
*/
public static Drawable getColorDrawable(Drawable srcDrawable, int color) {
srcDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
return srcDrawable;
}
imageView.setImageDrawable(DrawableUtil.getColorDrawable(ContextCompat.getDrawable(this, R.drawable.ic_arrow_back_white), Color.MAGENTA));
效果图如下:
注意:默认情况下,所有的drawable对象,加载相同的资源会共享状态。如果其中一个对象修改了状态,其它的对象也会收到相同的修改。要避免这种情况,应当设置drawable为mutable:
ContextCompat.getDrawable(this, R.drawable.ic_arrow_back_white).mutate()
这样就可以保证不与其它的drawable共享它的状态。
drawable文件的存放目录结构如下所示:
上面六种不同的drawable文件夹对应着六种不同的屏幕密度,它们的对应关系如下:
这里的屏幕密度指的是:
屏幕物理区域中的像素量;通常称为 dpi(每英寸 点数)。例如, 与“正常”或“高”密度屏幕相比,“低”密度屏幕在给定物理区域的像素较少。
在存放drawable资源时候,不同大小的图片放在不同的drawable-*dpi文件夹下。在一定程度上,设备会根据不同屏幕密度进行不同的缩放:
默认情况下,Android 会缩放位图可绘制对象(.png、.jpg 和 .gif 文件)和九宫格可绘制对象(.9.png 文件),使它们以适当的 物理尺寸显示在每部设备上。例如,如果您的应用只为 基线中密度屏幕 (mdpi) 提供位图可绘制对象,则在高密度 屏幕上会增大位图,在低密度屏幕上会缩小位图。这种缩放可能在 位图中造成伪影。为确保位图的最佳显示效果,应针对 不同屏幕密度加入不同分辨率的替代版本。
那么如果只给了一张图片资源,应该尽量放在适配高密度drawable文件夹下,因为在低密度设备上,即使缩小图片,它的分辨率也会很高,不会容易模糊。反而,如果图片放在低密度drawable文件夹下,在高密度设备上就会进行放大,图片将模糊。
图片在设备上的缩放比例:120:160:240:320:480:640=3:4:6:8:12:16,所以如果放一张96x96的图片在drawable-xhdpi文件夹下时,它在ldpi屏幕上是36x36,mdpi屏幕上是48x48,在hdpi屏幕上是72x72,在xxhdpi屏幕上是144x144,在xxxhdpi屏幕上是192x192。
现在放一张310x220的图片在drawable-xhdpi文件下,它在xxhdpi和xxxdpi屏幕密度上显示的结果如下:
由此可见,在xxhdpi屏幕上放大了1.5倍,在xxxhdpi屏幕上放大了2倍。
有时,背景只是一个单纯色,那么并不需要图片资源,只需要用颜色就可以实现背景的normal和pressed状态。
在/drawable/arrow_back_selector.xml文件中:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/colorAccent" android:state_enabled="true" android:state_pressed="true"/>
<item android:drawable="@android:color/transparent" android:state_enabled="true"/>
selector>
代码设置: imageView.setBackgroundResource(R.drawable.arrwo_back_selector);
效果如下:
在项目中,如果需要使用圆角图片,为了适配问题,不要引入UI设计切好的圆角图片,应使用代码进行圆角裁剪。
ImageView imageView = (ImageView) findViewById(R.id.image_view);
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.me);
RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(getResources(),((BitmapDrawable)drawable).getBitmap());
roundedBitmapDrawable.setCornerRadius(getResources().getDimensionPixelSize(R.dimen.size_2dp));
roundedBitmapDrawable.setAntiAlias(true);
imageView.setImageDrawable(roundedBitmapDrawable);
RoundedBitmapDrawable
位于support v4 包的android.support.v4.graphics.drawable中。
参考文档:
1.可绘制对象资源
2.支持多种屏幕