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;
}
});
}
}