在做移动中间件的过程中,遇到了背景图片自适应的问题,比如一个Button的背景图片,如何让一张图片能够在不同高宽的场景下做到不失真。
在做移动中间件的过程中,遇到了背景图片自适应的问题,比如一个Button的背景图片,如何让一张图片能够在不同高宽的场景下做到不失真。
方案一: 刚开始想到的一个方案是用android的 nine-patch (又称“九妹”),*.9.png的图片是标准的png格式的图片,只是在外边1px的区域增加了边框,定义了缩放区域,只有上方黑线和左边黑线的交会区域会被拉伸,如下图所示:
将图片放在 drawable 目录下,本文中我以一个项目为例子去比较出加载的效果,在一个页面里设置两个button,一个用点9的图片,另一个用普通的图片,运行后的效果如下,从图上可以看到,点9的图片实现了背景缩放不失真,达到了想要的效果。
但往往事情并不是那么简单就可以解决的,在我们开发过程中,我们的产品在用户使用的过程中,图片是放在自定义目录下的,而没有放在drawable目录下,发现即使是点9的图片也是没有生效,而且周围的黑线还在。后来研究发现点9的图片在apk打包的过程中,对图片进行了编译处理,而放在自定义目录下的图片并没有编译,故上述方案没有解决根本问题。
方案二:上述方案没有解决问题,后来思考到,既然android在打包的时候将图片编译处理成了没有黑线的图片,那么我可不可以对普通的图片进行类似的处理呢?
带着这个疑问,我研究了android ninepath图片的信息,发现这个.9.png的图片的头被写入了一部分信息,也就是记录了缩放位置的基本信息,即通过如下方法
byte[] chunk = bm.getNinePatchChunk();
StringBuilder sb = new StringBuilder();
int peddingLeft = getInt(chunk, 12);
int paddingRight = getInt(chunk, 16);
int paddingTop = getInt(chunk, 20);
int paddingBottom = getInt(chunk, 24);
拿到了点9图片的头信息,通过对头信息的分析处理,通过如下代码,可以看出其头信息里写入的即是 图片的padding及 x,y的值。
/**
* 生成ninepatch 图片的data区域的数据
* @param bm
* @param xBegin x开始点坐标
* @param xEnd x结束点坐标
* @param yBegin y开始点坐标
* @param yEnd y结束点坐标
* @return 缩放图片数据区
* @throws IOException
*/
public static byte[] getChunk(Bitmap bm,int xBegin,int xEnd,int yBegin,int yEnd) throws IOException{
int bmWidth = bm.getWidth();
int bmHeight = bm.getHeight();
int paddingLeft = xBegin;
int paddingRight= bmWidth-xEnd;
int paddingTop = yBegin;
int paddingBottom = bmHeight-yEnd;
ByteArrayOutputStream ooo = new ByteArrayOutputStream();
for (int i = 0; i < 32; i++) ooo.write(0);
writeInt(ooo, xBegin);
writeInt(ooo, xEnd);
writeInt(ooo, yBegin);
writeInt(ooo, yEnd);
for (int i = 0; i < 3 * 3; i++) writeInt(ooo, NO_COLOR);
byte[] data = ooo.toByteArray();
data[0] = 1;
data[1] = (byte) 2;
data[2] = (byte) 2;
data[3] = (byte) 3*3;
writeInt(data, 12, paddingLeft);
writeInt(data, 16, paddingRight);
writeInt(data, 20, paddingTop);
writeInt(data, 24, paddingBottom);
return data;
}
那么我只要将ninepatch 需要的值写入到图片中即可,经过研究,,通过给定的坐标,算出padding值写入的数
据区中,关键代码实现如下(详细见附件):
在测试demo中,我做了三个Button对比,运行效果如下图所示,第三个Button的背景图片和互一个Button是一样的,只是第三个使用了自定义拉伸,可看出圆角没有失真。
到此,对于一张普通的图片,只需要设置其拉伸区域的坐标,就可以实现圆角背景图片自适应且不失真,统一了移动平台Android和IOS对于图片缩放接口。(示例见附件testnine.zip)