关于.9图失效以及.9图不可以错过的细节点

Nine Patch Pic

.9图作为Android端图片控制的一个利器,使用的时候很简单,只需要在一个图片的四边预留1px的空白像素,然后按照规则,分别在left top right bottom控制这些1px像素就好了。

  • left: Vertical拉伸控制像素,可以为一个像素,也可以是一个区域
  • top: Horizontal拉伸控制像素,可以为一个像素,也可以是一个区域
  • right: Vertical内容区域,设置该.9后,控件的内容只能在这部分空间内显示
  • bottom: Horizontal内容区域,设置区域后,控件的内容只能在这部分空间内显示

这上面就是一个开发者对NinePatch最基本的认知,但是实际上NinePatch虽然用着简单,但是踩坑点实际还是存在的。Android NinePatch官方说明

在AndroidStudio提供的.9图生成器,实际上是一个熟悉的.bat文件,在以前很久之前.9图就是这样生成的。工具基于SDK目录下的draw9patch.bat做了封装整合到AndroidStudio中。同时说明下如下的这些功能

  1. Show Lock (显示当前.9图不可编辑的部分,一般都是非透明像素部分,即图片left top right bottom 留下的1px空白像素)
  2. Show Content (显示当前.9图内容区域,由right和bottom控制的内容区域)
  3. Show Patches (显示当前.9图拉伸区域,由top和left控制的拉伸区域)
  4. Show Bad Patches (显示当前.9图不规范的拉伸区域,由一套逻辑控制,等下详细说明)

NinePatch 在不同分辨率遇到的问题


Nine Patch遇到了问题?

需求描述:在使用NinePatch的一个场景中,UI给了一张背景图,我和UI都意在拉伸这张图片的空白区域,以实现内容的控制,同时可以保持头部的红色区域部分不变化。


切图的心路历程:

  1. 因为历史需求是需要这张图片作为背景图的,所以UI就针对这张背景图做了一个.9的处理
  2. 第一次切图,直接在原图上面的边距上面加了一个px的黑色像素,但是发现这样有问题,所以就有踩坑记录一了。
  3. UI小哥修改之后,直接Copy到项目,发现还是出现问题,他把多余的透明像素都换成了黑色像素,所以有踩坑记录二。
  4. 最后发现这个图片拉伸失效,虽然图片确实设置了.9拉伸了,但是又因为设置的vertical content区域是全部,所以红色的头部也会被拉伸
  5. 之后叫UI再次缩小空白区域,然后vertical content设置到红色区域下方

踩坑记录一:边缘留白透明像素,导致拉伸失效问题

踩坑描述:copy UI小哥的图片之后,发现整个背景图被拉伸了,而且观察效果发现图片左侧有两条黑边,和没有设置.9图一样。后来仔细观察.9图发现,发现.9图的左右侧的黑色

透明像素的.9图

透明像素的效果图

踩坑记录二:com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details

踩坑描述:在使用.9图之后,尝试通过gradle去Sync Project后,会提示这个错误。发现项目在clean、rebuild、Invalid Cache and Restart操作后均无效,还是会报同样的错误。思考后发现,当前操作只是Copy了UI提供的.9图,于是查看.9图是否存在猫腻。


果真,.9图原本预留的一个1px,UI切图后发现,right留白的像素不为1,而是2个黑色像素


两个黑色像素的.9图


踩坑一和二犯了一个最大的错误,违反了官方文档NinePatch的操作定义


看到官网指导的第四点,明确指定操作的px只有一个px,所以额外指定多px的话,可能会出现我上面描述的这些问题

官方NinePatch操作定义

踩坑记录三:缩小verticalContent还是遇到手机兼容的问题

经过上面的两个踩坑点,UI小哥乖了很多。切图只是切1px的内容了,也按照要求把verticalContent设置到了红白区域之间。切图从No1切到了No2

要求切的两张图

UI给的切图No.1
UI给的切图No.2


这时候按照平时的.9来说,已经满足UI的需求了,但是当项目跑起来的时候,实锤打脸。屏幕dpi较低的机型,头部的红色区域块还是会拉伸。

最后才有一个觉悟:即使图片控制了拉伸区域,但是他的其他部分都是不可拉伸的。所以白色区域的确是拉伸了,但是在高dpi上面加载低dpi的图片,那么图片肯定会被拉伸的。


最后需要UI小哥再根据主流的分辨率做了分别的切图,才真正的解决了这个问题


参考链接:不同dpi下的.9图

2xh.9图
3xh.9图


Bad Patch背后的逻辑

刚刚上面说了左上控制拉伸,右下控制内容填充。

.9图的边缘控制


按照官方的文档说明(简直不要太简单):在.9工具使用的时候,选中show bad patches按钮,图片会显示红色的区域块,红色区域块标识这块内容为"脏区域",而且"脏区域"仅仅会作用于拉伸区域(即左上区域)。 那这个"脏区域"会引起什么问题呢?

官网解释是这样:Visual coherence of your stretched image will be maintained if you eliminate all bad patches.
当所有的bad patches都消除之后,才能保持图片拉伸区域的一致性,所以换句话说=> 不消除"脏区域"可能会导致填充区域不能响应拉伸区域,所以图片就会不一致;但是假若图片在.9拉伸预览的时候,显示正确就没多大问题了,也不需要过多担心


虽然Stack Overflow 的这个NinePatch Bad Patches Pose说到不影响渲染,但是既然出现了这个问题,还是消除好一点。
,后面Google找到关于bad patches的产生与影响的点,这边贴下bad patches的pose
NinePatch Bad Patches 思考


Bad Patches是如何产生的?

例如有这样一张图,bad patches的产生只是发生在拉伸区域,所以我们需要关注的是left和top区域

原图


假若我们将left和top的拉伸区域,先放到一个简单的维度查看(只看top或者只看left),然后将这块区域切片再重叠,那将得到类似这样的一张图片,left和top拆分后,会分成若干个区域


left拆分


最后可以划分出8个区域,A,B,C,D,E,F,G


left top拆分后叠加


然后再将这八个区域进行1px的像素值进行划分,top区域进行水平划分,left区域进行垂直划分


垂直-叠加后拆分
水平-叠加后拆分




切片之后,Android Studio会先从top区域横向对比当前区域的所有像素值,检查是否一致。然后再从left区域纵向对比当前区域的所有像素值,检查是否一致。
假若不一致的情况下它就是bad patches。那么他要检查得多细致呢?一个颜色值的差别都算,虽然肉眼看出来颜色很相似,但是差别一个颜色值也是差别.


Bad Patches颜色值差异


那么他是怎么实现对比呢?,那垂直方向为例,垂直方向的切片会在这A B C E H这几个区域里面横向检查,去检查每一块切片的像素是否完全一致。假若组内像素值不一致,那么这个组就是一个 bad patches


image


同样滴,水平方向也是如此,会在C D E F这四个区域里面垂直检查每个切片的像素是否完全一致。假若组内像素值不一致,那么这个组就是一个 bad patches


image


那么至于交叉的部分C E,则需要检查两次,即垂直方向要检查一次,水平方向也需要检查一遍,假若组内像素值不一致,那么这个组就是一个 bad patches

例子验证

上面的pose主进行了一次测验,测验如下:

创建了十张不同的.9图,每张.9图在不同的区域里面均有像素值的差别。那bad patches就在这些区域上面展示出来了

测试Images.9


但是也存在一个特殊的例子,例如一张这样的图片,也是一张很常见的图片,带阴影的.9图。按照上面所说的:AndroidStudio会检查组里面的全部像素值是否一致,但是阴影一般都是多个不同色值的像素组成的,所以尽量拉伸值

带阴影的.9图
阴影放大之后

遇到.9图 bad patches需要怎么处理?

Pose主和Stack Overflow的回答都是比较直接:Google对bad patches的解释太隐晦了,只是简单解释会引起图片拉伸和内容区域不一致。但是Pose主都认为,假若在预览情况下面发现bad patches的话,先看看右侧的预览是否正确,假若预览正确的情况下那可以直接忽略bad patches了。

存在 bad patches的预览图


但是这里有一个更好的办法:

假若图片拉伸区域简单,那么请把left和top的拉伸像素值设置成1px,都可以直接避免bad patches的产生。
解释:按照上面bad patches产生的原因,因为垂直方向和水平方向的像素值只有1,所以group也只有一个,不能作为横纵向对比。那么他们只剩下一个交叉区域的对比了,但是交叉区域又是1个px的,所以也没有对比可言,所以就不会产生bad patches了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 MySQL 中,使用局部变量可能导致索引失效的情况通常涉及到查询语句中的变量赋值和索引的使用方式。以下是一些常见的情况: 1. 变量赋值导致索引失效:当在查询语句中使用局部变量进行赋值操作时,MySQL 无法在编译阶段确定变量的值,因此无法使用索引来优化查询。例如,使用 `SET` 命令将变量赋值后再使用该变量进行查询,这样可能会导致索引失效。 2. 函数对变量的操作导致索引失效:当在查询语句中使用函数对局部变量进行操作时,MySQL 无法利用索引来优化查询。这是因为函数的操作可能会改变变量的值,导致无法准确匹配索引。 3. 强制类型转换导致索引失效:当在查询语句中对局部变量进行强制类型转换时,MySQL 无法使用索引来优化查询。这是因为强制类型转换会改变变量的数据类型,导致无法匹配索引中保存的数据类型。 为避免索引失效的情况,可以考虑以下几: 1. 尽量避免在查询语句中使用局部变量进行赋值操作,尽量直接使用常量或参数。 2. 尽量避免在查询语句中使用函数对局部变量进行操作,可以考虑在应用程序中预先计算并传入结果。 3. 尽量避免在查询语句中对局部变量进行强制类型转换,可以考虑使用合适的数据类型来避免类型转换。 4. 根据具体情况,考虑是否需要重新设计查询语句、优化索引或调整表结构等操作,以提高查询性能。 总的来说,避免在查询语句中过多依赖局部变量的赋值、函数操作和类型转换,能够减少索引失效的潜在问题,提高查询性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值