引子
小u啊,我们应用启动的时候有一段白屏,不雅观,你给整个启动图上去,给,这里是资源图片
换好了
嗯,不错不错,咦,这个小米fold怎么显示了两个logo数组的定义?
啊?这。。。我来看看
是这样的,activity启数组初始化动图和启动背景图标一起显示了,但是启动图片又不适配fold这数组的定义种狭长的屏幕,而且下半部分由于没有背景,是透明的,所以就显示了两个图标,一个启动图标,一个启动图图片图标,请看示意图
那怎么解决呢?
有几个办法,数组的定义1.让启动图拉伸,覆盖下部分区域,但是会数组c语言有形数组初始化变,不够优雅,2.给imageview设置一个白色背景,让数组的定义它不透明,3.使用android studio的。9图片制作工具,让空白部分拉伸,内容不拉伸,非常优雅。
好,那你先试试.9图片吧
.9简介
我知道看这篇文章的朋友肯定对.9图或多或少有点了解,就简单介绍下就行 .9图可以通过设置来让图片某一部分拉伸 其他部分不拉伸 还可以控制图片里面显示内数组初始化容的区域 这就是.9图的简介 够简了吧 如果想看更详细的说明可以移步谷歌官方的说明 大体上也是这意思
这个是官数组词方的文档developer.android.com/studio/writ…
这是.9图在数组去重方法三种拉伸情况下的例子,纵向,横向,横数组去重方法纵双向。
.数组去重9图制作
网上很多文章说最简单是用as内置工具来做 但是数组排序网上文章好多都是很早的 都是老版本工具 让我们来看看这工具现在啥样
好像也不是很简单啊 这些东西做什么用的第一次看确实会很蒙,这里介绍下这个工具
-
Zoom:调数组去重方法整图形在绘制区域中的缩放级别。
-
Patch scale:调整图像在预览区域中的比例。
-
Show l数组和链表的区别ock:当鼠标悬停在图形的不可绘制区域上时以直观方式呈现。
-
Show patches:预览绘制数组去重方法区域中的可拉伸图块(粉色数组去重方法为可拉伸图块),如上面的图 2 所示。
-
Show content:突出显示预览图像中的内容区域数组的定义(紫色为允许绘制内容数组的定义的区域),如图 2 所示。
-
Show bad patches:在拉伸时可能会在图形中产生伪影的图块区域周围添加红色边框,如图 2 所示。如果您消除所有不良图块,已拉伸图像的视觉连贯性将得以保持。
怎么生成.9图不是重点,网上文章不要太多,最主要就是绘制左边和上面的黑线,左边黑线控制的是哪里可以被上下拉伸,上面黑线控制哪里可以被水平拉伸,可以有多条数组排序,右边和下面的黑线控制了哪里可以放内容,不在这个区域的内容不会被显示。
当然 还有很多办法生成.9图 单独工具或者在线工具都行 看个人喜好了。
.9图原理
上面的介绍都很数组指针大众化 那么为啥.9图这么神数组去重方法奇呢?它是什么原理呢,这个好像没什么数组和链表的区别人说过,这里也简单阐述下。
主要是四条黑线 分为两组 左边和上面的黑线 负责判定图片哪个部分可以被拉伸 右边和下面的黑线 负责确定图片内部展示内容的区域 比数组公式如这个图是个聊天气泡 内容是一堆文字
大概就是下面这个图的样子 分成了九个区域
我们把他们编号成1-9,这几个区域对应情况如下
- 1 3 7 9 号区域,不在两条黑线区域内,不会被拉伸
- 4 6 号区域,只在左侧黑线范围内,可以被上下拉伸
- 2 8 号区域,只在上面黑线区域内,会被左右拉数组初始化伸
- 5号区域,同时在上和左区域内,会被上下左右拉伸
回到刚才的问题 为啥处理之后就能控制拉伸数组去重方法和内容了?
首先我们发现处理之后的图片后缀还是原来数组指针的 证明没有变成其他格式 但是名字里加上了.9数组c语言
那猜测是不是在文件里加上了一些额外信息 用.9作为数组c语言标识 图片系统处理拉伸的时候就去读这些信息
那么 到底加了什么信息呢 又是怎么判断和使用的呢 下面一一道来
首先 我们给图片加了什么信息
我们看看官方怎么描述.9图的
NinePatchDrawable
图形是一种可拉伸的数组c语言位数组去重图,可用作视图的背景。Android 会自动调整图形的大小以适应视图的内容。NinePatch 图形是标准 PNG 图片,包含一个额外数组排序的 1 像素边框。必须使用9.png数组去重
扩展名数组公式将其保存在项目的res/drawable/
目录下。
可以看到,.9图本质上还是png图片,但是加了1像素边框,且名字里加了个.9。
让我们来看看什么是png图片,以及它的数据构成
The PNG format provides a portable, legally unencumbered, well-compressed, well-specified standard for lossless bitmapped ima数组ge files.
A PNG file consists of a PNG signature followed by a se数组ries of chunks. This cha数组词pter defi数组c语言nes the signature and the basic properties of chunks.
png的签名块后面跟了两个数据块数组和链表的区别crit数组初始化ical chunk和ancillary chunks,其中critical chunk包含数组公式关键数组指针数据,也是每个图片必须有的,ancillary chunks包含一些辅助信息,png如果不识别这些辅助块,可以忽略它打到数组公式向下兼容的目的。数组词
签名块就是一个八个字节的十六进制码,用来数组标识图片。
重点来看看数据块的布局
名称 | 字节数 | 说明 |
---|---|---|
长度(L数组ength) | 4字节 | 指定数据块中数据区域的长度,长度不可超过(231-1)个字节 |
数据块类型码(Chunk Type Code) | 4字节 | 数据块类型码由数组初始化AS数组词CII字母(A-Z和a-z)组成的”数据块符号数组的定义“ |
数据块数据(Chunk Data) | 可变长度 | 存储数据块类型码指定数组指针的数据 |
循环冗余检测(CRC) | 4字节 | 存储用来检测是否文件数组c语言传输有误的循环冗余码 |
看到这个可以猜测,我们添加的黑色边框就是往辅助块里面加了内容,在展示的时候识别添加的信息,达到控制哪些地方伸缩的目的。
让我们看看一张图片被弄成.9之后加了些什么内容。
原图数据如下
.9数据如下
可以看到,变成.9图片之后,多了5个数组去重方法ID数组排序AT块,而且参数里面的长宽都增加了2像素,而且图片大小也增加了不少从80kb增加到了180kb,我们可以猜测到,这几数组公式个块里面记录的数据就是我们生成.9图时画的那几条线生成的了。
其次 这些信息在图片发生拉伸时怎么被识别和使用的
这就涉及到andro数组和链表的区别id怎么加载一张图片的问题了,当然这些操作都是native层进行的,经过代码跟踪,我们发现有这样一个类 ** NinePatchPeeker.cpp**
我们来看看这个类里面的readChunk方法干了些什么
bool NinePatchPeeker::readChunk(const char tag[], const void* data, size_t length) {
if (!strcmp("npTc", tag) && length >= sizeof(Res_png_9patch)) {
Res_png_9patch* patch = (Res_png_9patch*) data;
size_t patchSize = patch->serializedSize();
if (length != patchSize) {
return false;
}
// You have to copy the data because it is owned by the png reader
Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize);
memcpy(patchNew, patch, patchSize);
Res_png_9patch::deserialize(patchNew);
patchNew->fileToDevice();
free(mPatch);
mPatch = patchNew;
mPatchSize = patchSize;
} else if (!strcmp("npLb", tag) && length == sizeof(int32_t) * 4) {
mHasInsets = true;
memcpy(&mOpticalInsets, data, sizeof(int32_t) * 4);
} else if (!strcmp("npOl", tag) && length == 24) { // 4 int32_ts, 1 float, 1 int32_t sized byte
mHasInsets = true;
memcpy(&mOutlineInsets, data, sizeof(int32_t) * 4);
mOutlineRadius = ((const float*)data)[4];
mOutlineAlpha = ((const int32_t*)data)[5] & 0xff;
}
return true;
}
我们数组排序看到这里处理了npTc
、np数组指针Lb
、npOl
三个数据块,当判断有npTc
这个数据块的时候,系统就认为这是.9图片,就会进行下一步处理。
那npTc
这个数据又是从哪来的呢?
从上面内容我们知道已经添加了一些额外信息,我们发现官方的说明里有一句,要把.9图放在src/drawable目录下,这是因为在编译的时候,aapt会在发现图片名字符合.9图规则的时候,把四周的黑色边框提取出来,放在npTc
数据块里面。
接下来我们看看结构体Res_png_9patch
里面有什么。
/**
* This chunk specifies how to split an image into segments for
* scaling.
*
* There are J horizontal and K vertical segments. These segments divide
* the image into J*K regions as follows (where J=4 and K=3):
*
* F0 S0 F1 S1
* +-----+----+------+-------+
* S2| 0 | 1 | 2 | 3 |
* +-----+----+------+-------+
* | | | | |
* | | | | |
* F2| 4 | 5 | 6 | 7 |
* | | | | |
* | | | | |
* +-----+----+------+-------+
* S3| 8 | 9 | 10 | 11 |
* +-----+----+------+-------+
*
* Each horizontal and vertical segment is considered to by either
* stretchable (marked by the Sx labels) or fixed (marked by the Fy
* labels), in the horizontal or vertical axis, respectively. In the
* above example, the first is horizontal segment (F0) is fixed, the
* next is stretchable and then they continue to alternate. Note that
* the segment list for each axis can begin or end with a stretchable
* or fixed segment.
*
* ...
*
* The colors array contains hints for each of the regions. They are
* ordered according left-to-right and top-to-bottom as indicated above.
* For each segment that is a solid color the array entry will contain
* that color value; otherwise it will contain NO_COLOR. Segments that
* are completely transparent will always have the value TRANSPARENT_COLOR.
*
* The PNG chunk type is "npTc".
*/
struct alignas(uintptr_t) Res_png_9patch
{
int8_t wasDeserialized;
uint8_t numXDivs, numYDivs, numColors;
uint32_t xDivsOffset, yDivsOffset, colorsOffset;
int32_t paddingLeft, paddingRight, paddingTop, paddingBottom;
enum {
// The 9 patch segment is not a solid color.
NO_COLOR = 0x00000001,
// The 9 patch segment is completely transparent.
TRANSPARENT_COLOR = 0x00000000
};
...
inline int32_t* getXDivs() const {
return reinterpret_cast<int32_t*>(reinterpret_cast<uintptr_t>(this) + xDivsOffset);
}
inline int32_t* getYDivs() const {
return reinterpret_cast<int32_t*>(reinterpret_cast<uintptr_t>(this) + yDivsOffset);
}
inline uint32_t* getColors() const {
return reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(this) + colorsOffset);
}
}
从注释我们看出,一张图片被分成了很多数组去重个部分,s开头的代表可以拉伸的,f开头的代表不能拉伸,还有一些颜色的数据,他们共同构成了这个结构体,x,y轴上这些可以拉伸和不可拉伸的部分分别放在数组xdiv
和ydivs
数组里,同时内容的显示数组初始化区域也由几个padding
来存放,到这里,就把.9图的额外信息数组公式都给读出来了。
既然已经获得了这些额外的信息,那么绘制的时候,系统就可以根据这些信息判断怎么拉伸一数组词张.9图了,绘制调用了NinePatchDrawable
,最终也会走到native层去处理这些数据。
到此为止,制作.9和解析.数组排序9的过程就分析完毕了,一张数组去重.9数组去重方法图背后居然这么复杂,还是挺数组指针让人意外的,果然是学无止数组去重方法境啊。
.9图应用以及一个小坑
看完了怎么生成和它的原理 该我们去使用它了 回到开头数组 用我们新做的酷炫.9图解决问题吧! 代码张这样
效数组指针果张这样
为什么我们的.9图没有按照预期的拉伸,而是把内容也给拉伸了?因为.9图的特性问题,它只支持拉伸,如果一个图片本身就比imageview数组排序大了,那就不会去拉伸,所以我们的.9图本身太大了,也数组去重方法就不数组指针存在拉伸的说法了,那肯定是无效的。 那我们再来尝试把图片尺寸改小,这下可以拉伸了吧,来看看效果。
可以看数组词到,下面图标被遮挡住了,但是内容也太小了吧,所以数组去重方法用.9图来做数组去重方法s数组的定义plash screen背景不是个好主意。
那么,到底哪些场景可以用它呢?总结一下就是,一张图片,角落不能拉伸,其他部分可以随着内容的增多随便拉伸的情况,像这样。
简单来说,就是聊天气泡一类的,如果一张图片的主体是内容要放缩的话,是不适合的,因为.9图只会拉伸特定部分,主体部分会数组去重方法维持原大小。
比如我们上面做背景数组的定义图这种情况。
总结
- .9图并不适合作为全屏展示页面,要不太大了没有拉伸效果,要不内容太小了不美观数组
- .9图适合做一些纯色拉伸不形变的背景,比如数组公式聊天气数组和链表的区别泡和按钮背景这种
- 在数组词andr数组指针oid中,.9图得放到sr/drawable目录才行,系统才会去生成对应数据块,才可以被解析,否则就要自己去生成
- 普通图片由于没有额外的数据,是不能达到.9图这样的效果的