背景

.9图来源于Android。为了设计出一套图,兼容Android和iOS,使用.9图的方式来对图片进行拉伸以适应不同的屏幕。在iOS中没有.9图的概念,只能先了解Android的.9图再进行模拟Android的方法。

什么是.9图片

即图片后缀名前有.9的图片,如pic.9.png、pic1.9.jgp,诸如此类的图片就称为.9图片。且在原始图片四周添加了一个像素,在这一个像素上用黑线标识出相关的区域。

.9图片的作用

.9图片的作用是在图片拉伸的时候特定的区域不会发生图片失真,特定的区域就是由.9图边缘一圈像素中的left和top的黑线所决定。

Android中的.9图介绍

.9图其实是在原始图片的四周添加了一个像素,通俗点说就是图片比原始图片扩大了一圈,多出来的那一圈是透明像素。我们需要绘制黑线的地方正是在那一圈透明像素上进行绘制。

如上图所示,在原始图的四周添加了一个圈的透明像素。其中:四周分别命名为L、T、R、B。

绘制在L的区域:用于拉伸的纵向区域。

绘制在T的区域:用于拉伸的横向区域。

绘制在R的区域:用于显示前景的纵向范围。

绘制在B的区域:用于显示前景的横向范围。

举例说明一下,如下图 :

该图的四周添加了相应的黑线。

拉伸区域,如下图:

红色框区域:表示纵向拉伸的区域,也就是说,当图片需要纵向拉伸的时候它会只指定拉伸红色区域,其他区域在纵向是不会拉伸的。

绿色框区域:表示横向拉伸的区域,也就是说,当图片需要横向拉伸的时候它会只指定拉伸绿色区域,其他区域在横向是不会拉伸的。

显然红色和绿色相交的部分是既会进行横向拉伸也会进行纵向拉伸的。

前景的显示区域,如下图:

蓝色区域:表示前景能显示的纵向范围。即前景的最上面可以显示到什么地方,最下面可以显示的什么地方。

黄色区域:表示前景能显示的横向范围。即前景的最左边可以显示到什么地方,最右边可以显示的什么地方。

蓝色和黄色相交部分:表示整个前景能显示的区域。一个区域是矩形的,蓝色规定了上下边界,黄色规定了左右边界,两者共同当然也就规定了一个矩形区域。

在iOS中图片拉伸:

1.在iOS5之前,使用- (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight;这个方法进行图片的拉伸。

2.在iOS5之后,使用- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets;

或- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode;这个方法进行图片的拉伸或平铺。

iOS中有个叫端盖(end cap)的概念,用来指定图片中的哪一部分不用拉伸。比如下图中,黑色代表需要被拉伸的矩形区域,上下左右不需要被拉伸的边缘就称为端盖。

如上所述,在iOS中想要拉伸图片,就得确定要被拉伸的区域,而这个区域是由top、left、bottom、right四个方向的值所决定的区域,这部分的概念与Android中的.9图是不太一样的,但拉伸的区域概念差不太多。

了解了以上概念,我们就可以在iOS中模拟Android处理.9图的拉伸模式。

我们使用了一个第三方库:LVNinePatchImage进行.9图的处理。因为原始图片四周添加了一像素的透明。而只有黑线的alpha值是为1的,其余部分都是透明的则alpha值为0。通过这种逻辑关系就能找到对应的左边和上边的黑线区域位置。然后通过iOS系统提供的拉伸方法进行图片的拉伸操作。

该库主要主要做的事有:

1.通过类方法+ (unsigned char*)getRGBAsFromImage:(UIImage*)image count:(NSInteger)count;来获取图片的所有像素点的RGB值包括Alpha值。

2.通过方法 inline static CGFloat getImageAphaAtPoint(const unsigned char* rawData, NSInteger width, NSInteger height , NSInteger pointX, NSInteger pointY);去找出pointX到pointY之间像素点的Alpha值。

如当pointY始终为0,pointX从1到图片的宽度,就能找出图片顶部一像素的所有alpha值。当pointX始终为0,pointY从1到图片的高度,就能找出图片左边一像素的所有alpha值。

3.然后遍历找到的顶部和左边的alpha数组值,当alpha为1的连续区域就是黑线的所在位置。

4.然后调用方法+ (UIImage*)crop:(CGRect)r image0:(UIImage*)image0;裁剪掉图片四周的一像素区域,只保留中间正确(最原始)的图片。

5.最后再根据黑线的所在位置,算出top、left、bottom、right端盖的值,调用- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets;方法进行图片的拉伸或平铺。

参考链接

http://blog.csdn.net/shimiso/article/details/41079847

http://www.cnblogs.com/mjios/archive/2013/02/26/2934280.html

iOS 中使用.9图的更多相关文章

  1. iOS中 轮播图放哪最合适? 技术分享

    我们知道,轮播图放在cell或collectionViewCell上会影响用户层级交互事件,并且实现起来比较麻烦,现在推出一个技术点:答题思路是:将UIScrollView放在UIView或UICol ...

  2. iOS中 动态启动图GIF的简单设置 韩俊强的博客

    // 设定位置和大小 CGRect frame = CGRectMake(50,340,[UIScreen mainScreen].bounds.size.width / 2,[UIScreen ma ...

  3. 解决iOS中 tabBarItem设置图片(image+title切图在一起)时造成的图片向上偏移

    解决iOS中 tabBarItem设置图片(image+title切图在一起)时造成的图片向上偏移 解决办法1:设置tabBarItem的imageInsets属性 代码示例: childContro ...

  4. iOS中数据库应用基础

    iOS 数据库入门 一.数据库简介 1.什么是数据库? 数据库(Database) 是按照数据结构来组织,存储和管理数据的仓库 数据库可以分为2大种类 关系型数据库(主流) PC端 Oracle My ...

  5. iOS开发——高级篇——iOS中常见的设计模式(MVC/单例/委托/观察者)

    关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...

  6. iOS 图片轮播图(自动滚动)

    iOS 图片轮播图(自动滚动) #import "DDViewController.h" #define DDImageCount 5 @interface DDViewContr ...

  7. (转)如何处理iOS中照片的方向

    如何处理iOS中照片的方向 31 May 2015 • 7 min. read • Comments 使用过iPhone或者iPad的朋友在拍照时不知是否遇到过这样的问题,将设备中的照片导出到Wind ...

  8. iOS中的存储方式

    1.Plist 1.1 了解沙盒 每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其它文件系统隔离.应用必须呆在自己的沙盒里.其它应用不能访问该沙盒. 一个程序中所有的非代码文件都可以 ...

  9. 浅谈iOS中的userAgent

    浅谈iOS中的userAgent   User-Agent(用户代理)字符串是Web浏览器用于声明自身型号版本并随HTTP请求发送给Web服务器的字符串,在Web服务器上可以获取到该字符串. 在公司产 ...

随机推荐

  1. HDU 4393 Throw nails

    Throw nails Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  2. Python中,如何初始化不同的变量类型为空值

    参考文章  Python中,如何初始化不同的变量类型为空值 常见的数字,字符,很简单,不多解释. 列表List的其值是[x,y,z]的形式 字典Dictionary的值是{x:a, y:b, z:c} ...

  3. A Pretty Good Splash Screen in C#

    http://www.codeproject.com/Articles/5454/A-Pretty-Good-Splash-Screen-in-C

  4. 恒天云技术分享系列2 - vlan管理GUI开发

    恒天云:http://www.hengtianyun.com/download-show-id-10.html 在OpenStack G版本中quantum网络模式下,horizon提供了基于quan ...

  5. [.NET]c#.net程序中使用ffmpeg.exe来处理视频并生成上传视频的截图

    添加如下前台代码: <asp:FileUpload ID="FileUpload1" runat="server" /> <asp:Butto ...

  6. CSU 1515 Sequence (莫队算法)

    题意:给n个数,m个询问.每个询问是一个区间,求区间内差的绝对值为1的数对数. 题解:先离散化,然后莫队算法.莫队是离线算法,先按按询问左端点排序,在按右端点排序. ps:第一次写莫队,表示挺简单的, ...

  7. AlertDialog

    1.AlertDialog点击时不自动消失 //在setPositiveButton和setNegativeButton根据自己的逻辑处理,大概代码如下 if(validate){//验证通过自动消失 ...

  8. A Tour of Go Function closures

    Go functions may be closures. A closure is a function value that references variables from outside i ...

  9. Bugs及解决方案列表

    Bugs及解决方案列表(以下实例默认运行环境都为Standard mode): 如何在IE6及更早浏览器中定义小高度的容器? 方法: #test{overflow:hidden;height:1px; ...

  10. C++学习笔记(十一):void*指针、类型转换和动态内存分配

    void*指针 void关键字表示“空类型”的概念.但是,这里的“空类型”不表示“任意类型”,而是表示不存在的意思,也就是说C/C++不允许你写语句void a,不存在类型为void的东西. void ...