Android 背景图片自适应方案

3年前

在做移动中间件的过程中,遇到了背景图片自适应的问题,比如一个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

COMMENTS

需要 后方可回复
如果没有账号可以 一个帐号。