持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
问题
为什么出现.9图
需求背景
其实本质上来说现有PNG只携带颜色的像素RGB信息已经不能很好的拓展了,所以需要额外的信息添加倒PNG格式下实现额外的图片功能。例如我们使用的图片需要是动态的修改宽高消息,或者修改的文字的显示区域 。
因此PNG格式中需要携带额外的信息,这部分信息该存储在哪里呢?
PNG格式
我们先看下PNG格式的构成,可以看到PNG格式在设计时就考虑到我们对于图片的额外需求了,只要将这些信息添加到对应的辅助块CHUNK中即可。
在文件头之外,PNG图片使用了基于“块(chunk)”的存储结构,每个块负责传达有关图像的某些信息。
块有关键块或辅助块两种类型,关键块包含了读取和渲染PNG文件所需的信息,必不可少。而辅助数据块则是可选的,程序在遇到它不理解的辅助块时,可以安全地忽略它,这种设计可以保持与旧版本的兼容性。
.9图的源类型和已编译类型
首先,我们要了解的是,在Android的世界里,存在着两种不同形式的点9图文件,分别是“源类型(source)”和“已编译类型(compiled)”。
源类型就是前面所提到的,使用了包括Draw 9-patch在内的点9图制作工具所创建的、四周带有1像素宽黑色边框的PNG图片。
因此源类型的.9图和普通的PNG图片没什么不一样,只不过上下作用多加了一像素的黑边。此时的额外CHUNK还没有利用到
而已编译类型指的是,把之前定义好的点九图数据(可拉伸区域&可绘制区域等)写入原先格式的辅助数据块后,把四周的黑色边框抹除了的PNG图片。
编译的过程只不过就是将.9图的四条黑边转换成了数据添加到额外的CHUNK中了
点九图数据所放入的,正是一个tag为“npTc”的辅助数据块。
AAPT对点九图做的预处理
AAPT在打包过程中对点9图的预处理,其实就是将点9图从源类型转换为已编译类型的过程,也只有已编译类型的点9图才能被Android系统识别并处理,从而达到根据视图内容自动调整图片大小的效果。
而直接从网络加载的点9图则缺少这个过程,我们实际拿到的是没有经过AAPT预处理的源类型,Android系统就只会把它当普通的PNG格式图片一样处理,因此展示时会有残留在四周的黑色边框,并且当视图内容过大时,图片就会因为不合理拉伸而产生明显的失真。
定义
点9图,官方的正式名称为9-patch,是一种可拉伸的位图图像格式,因其必须以.9.png为扩展名进行保存而得名,通常被用作各类视图控件的背景。
其典型的一个应用就是IM中的聊天气泡框,气泡框的宽高会随着我们输入文本的长短而自适应拉伸,但气泡框资源本身并不会因拉伸而失真。
这么神奇的效果是怎么实现的呢?
答案是:四条黑线。
忽略掉.9.png的扩展名,点9图的本质其实就是一张标准的PNG格式图片,而与其他普通PNG格式图片的不同之处在于,点9图在其图片的四周额外包含了1像素宽的黑色边框,用于定义图片的可拉伸的区域与可绘制的区域,以实现根据视图内容自动调整图片大小的效果。
可拉伸区域的定义
可拉伸区域由左侧及顶部一条或多条黑线来定义,左侧的黑色边框定义了纵向拉伸的区域,顶部的黑色边框定义了横向拉伸的区域,拉伸的效果是通过复制区域内图片的像素来实现的。
可以看到,由于可拉伸区域选择的都是比较平整的区域,而没有覆盖到四周的圆角,因此图片无论怎么纵向或横向拉伸,四周的圆角都不会因此而变形失真。
可绘制区域的定义
可绘制区域由右侧及底部的各一条黑线来定义,称为内边距线。如果没有添加内边距线,视图内容将默认填满整个视图区域。
而如果添加了内边距线,则视图内容仅会在右侧及底部的黑线所定义的区域内显示,如果视图内容显示不下,则图片会拉伸至合适的尺寸。