android设置背景图片默认会被拉伸至填满视图大小,试过使用.9图,但在线性布局不生效,最后找到一种解决方式,将图片缩放以保证在一个方向充满,另一方向使用空白像素填充,注意*图片拉伸方向边界一定要为透明或背景色。
首先使用BitmapFactory.decodeResource生成背景图Drawable(没如果不是资源文件使用其他对应方法),设定BitmapFactory.Options在生成图片的同时完成图片的缩放。Options中默认只能通过inSampleSize设定缩小的倍速(2的整数倍),显然无法满足需求,在inScaled属性的注释上可以看到:
当此标识位设定为true时,如果inDensity和inTargetDensity属性值均不为0,bitmap将在加载时进行缩放,适配inTargetDensity大小,而不是在每次绘制时进行缩放。若使用BitmapRegionDecoder则会忽略这个标记,不会基于密度缩放(虽然支持通过inSampleSize设置缩小)。当此标识默认为true,如果需要,应该关闭。点9图将忽略此标示,总是进行缩放。如果inPremultiply设置为false,且图像有alpha值,则将此标识设置为true可能导致错误的颜色。
因为通过一下两步完成缩放计算:
①:设置Options中inDensity为系统densityDpi(context.getgetResources().getDisplayMetrics().densityDpi);
②:根据缩放计算Options中inTargetDensity的值(目标视图宽度 /图片宽度) * inDensity值)
此时通过public static BitmapdecodeResource(Resources res, int id, Options opts)方法完成背景图片的创建,下一步,设置背景图填充模式--->Shader.TileMode。
Shader.TileMode枚举类一共分为3种:
1、CLAMP (0),使用图片边界像素填充视图空白部分,默认为右边界和下边界;
2、REPEAT (1),重复图片填充空白;
3、MIRROR (2),使用图片镜像填充空白;
根据前面确定的解决方案,调用BitmapDrawable的public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode)方法,设置拉伸模式均为 Shader.TileMode.CLAMP。
完整实现代码如下:
public static void setClampBgDrawable(final View targetView, int resId, Resources res, boolean clampX) {
setClampBgDrawable(targetView, resId, res, clampX, true);
}
private static void setClampBgDrawable(final View targetView, final int resId, final Resources res,
final boolean clampX, boolean tryOnPreDraw) {
int targetWidth = 0;
if (targetView instanceof RecyclerView) {
RecyclerView.LayoutManager manager = ((RecyclerView) targetView).getLayoutManager();
if (manager != null) {
targetWidth = manager.getWidth();
}
} else {
targetWidth = targetView.getWidth();
}
if (targetWidth > 0) {
//测量图片实际大小
BitmapFactory.Options measureOpts = new BitmapFactory.Options();
measureOpts.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, measureOpts);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inDensity = res.getDisplayMetrics().densityDpi;
opts.inTargetDensity = targetWidth * opts.inDensity / measureOpts.outWidth;
Bitmap bitmap = BitmapFactory.decodeResource(res, resId, opts);
//不能使用过时的构造方法,否则可能会不生效
BitmapDrawable bgDrawable = new BitmapDrawable(res, bitmap);
//设置填充模式,由于X轴充满视图,所以TileMode可以为null
if (clampX) {
bgDrawable.setTileModeXY(Shader.TileMode.CLAMP, null);
} else {
bgDrawable.setTileModeXY(null, Shader.TileMode.CLAMP);
}
bgDrawable.setDither(true);
targetView.setBackground(bgDrawable);
} else if (tryOnPreDraw) {
targetView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
targetView.getViewTreeObserver().removeOnPreDrawListener(this);
setClampBgDrawable(targetView, resId, res, clampX, false);
return false;
}
});
}
}
网友评论