上回书介绍了Android平台用于拉伸的.9图,程序通过识别.9图中的1像素边界来达到自动拉伸图片的效果。那么在iOS平台中,图片拉伸的原理和思路基本与.9图相似,也是通过设定上下左右的安全区来定义图片拉伸的区域,只不过在iOS平台上,拉伸图片的工序基本是需要程序猿来达成,通过代码或者可视化的方式来设定安全区。
本文中将介绍代码实现图片拉伸的方式。
目前,代码拉伸的方式有3种,分别是iOS5之前、iOS5之后、iOS6之后的三种方法,但iOS5的方法已经过期,iOS6之后的方法比iOS5之后的方法更优,因此,本文只介绍iOS6之后最新的方法。想要了解iOS5之前、iOS5之后的方法,请在后台回复001查看本文的番外篇。
在苹果开发者网站中,有关于设定可拉伸图片的部分:
([UIImage - UIKit | Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uiimage))
笔者翻译:
定义可拉伸图像
可拉伸图像划定了可以被复制的区域,在此区域内,底层图像数据可以以一种美观的方式被复制。可拉伸图像经常用来创建可拉伸或缩小的背景,以填充可用的区域。
你可以通过给图像添加内嵌(insets)来将它定义一个可拉伸图像,具体可以使用两种方法,即resizableImage(withCapInsets:) 或 resizableImage(withCapInsets: resizingMode:)。内嵌(insets)将图像划分成两个或多个部分。给每个内嵌(insets)区域指定非零的值,将图像分为9个部分,如图1所示。
图1 使用内嵌(insets)来定义可拉伸图像
每一个内嵌(insets)定义了图像上不被拉伸的部分,在图片顶部和底部的内嵌(insets)区域将保持一个固定的高度,在左边和右边的内嵌(insets)区域将保持一个固定的宽度。图2展示了当图像在填充可用区域时,9个部分各自将如何拉伸。图像的四角不会有大小变化,因为它们均处于纵向和水平的内嵌(insets)区域内。
图2 九宫格图像的拉伸区域
不难看出,iOS平台上的图像拉伸与Android平台中的图像拉伸原理十分相似,都是将图像划分为9宫格,在各个方法做拉伸,只不过Android靠点九图中的黑色边线来标识拉伸的部分,iOS则利用代码或者是在编译器中进行可视化的编辑。具体来说是通过给图像定义四个内嵌(insets),从而将图像划分为九宫格再进行拉伸。
接下来将介绍上文提到的两种拉伸方法
resizableImage(withCapInsets:)
官当文档:
笔者翻译:
实例方法:resizableImage(withCapInsets:)
创建并返回一个设定有指定端盖内嵌(cap insets)的新图片对象
声明:
func resizableImage(withCapInsets capInsets: UIEdgeInsets) -> UIImage
参数:
capInsets —— 端盖内嵌(cap insets)的数值
返回数值:
一个设定有指定端盖内嵌(cap insets)的新图片对象
描述:
你可以使用这个方法来给图像添加端盖内嵌(cap insets),或是改变一个图像已有的端盖内嵌(cap insets)。无论哪种情况下你都会得到一个新的图像,同时原始图像将不受影响。比如说,你可以使用这个方法为一个带边界和圆角的按钮创建背景图像:当按钮被缩放时,图像的四角将不会改变,但图像的边界和中间将拉伸以填充新的大小。
iOS不同的渲染技术有着不同的表现特征,这取决于图像中每个拉伸区域的大小:
如果拉伸区域有1像素宽或高,则横向拉伸区域是1像素宽,纵向拉伸区域是1像素高,换言之,图像中心区域为1x1像素大小,iOS将通过拉伸这1像素来绘制新的图像。这种模式将有最快的表现(在端盖内嵌(cap insets)非零的情况下)。
如果拉伸区域的宽或高大于1像素,iOS将以平铺(tiling)的方式填充。这种模式表现相对较慢,但对于纹理图像(非固色)的填充来说非常实用。
如果整个图像都被拉伸,这种情况下capInsets的参数为UIEdgeInsetsZero,它的尺寸也会大于1x1像素,iOS将通过平铺整个图像来绘制新图像。这种模式在端盖内嵌(cap insets)非零的情况下,将会比平铺(tiling)的方式更快。
如果要直接控制拉伸的模式,请使用resizableImage(withCapInsets: resizingMode:)方法。
在方法介绍中提到的参数capInsets是UIImage的一个属性,用以设定图像的端盖内嵌(cap insets)
capInsets
官当文档:
笔者翻译:
实例属性:CapInsets,即端盖(end-cap)内嵌(insets)。
声明:
var capInsets: UIEdgeInsets { get }
描述:
端盖指定了在图片拉伸时,不会被拉伸的区域。该技术应用于按钮以及其他可调整大小的界面图片元素。当带有端盖的按钮被拉伸时,只会被拉伸按钮的中部,也就是各端盖之间的区域。而端盖则会保持其原始的大小和外观。
CapInsets属性指定了4个端盖的大小,中间(可拉伸)区域由所有不包括在端盖的像素组成,这些像素将会以tiled(瓷砖)的方式从左向右、从上到下来填充其余的空间。
在一个不可拉伸的图片中,CapInsets属性被设置为UIEdgeInsetsZero,因而图片不会使用端盖,这也导致在拉伸时是整个图片作为整体被拉伸。若想要创建一个CapInsets属性不为零的图片,则使用resizableImage(withCapInsets:)方法。如果你的应用程序将UIEdgeInsetsZero指定为CapInsets的参数,那么就将整个图片设为平铺(tiled)。
CapInsets即是包含端盖(end-cap)图片,end up(端盖)在iOS中是指在图片中不被拉伸的区域。
而CapInsets的变量类型是UIEdgeInsets.
UIEdgeInsets
官当文档:
笔者翻译:
数据结构:UIEdgeInsets,即界面的嵌入式间隔距离。
概述:
边界内嵌的数值将用于缩小或扩展矩形所表示的区域。通常,边界内嵌应用于界面布局,以此调整界面框架。正值使框架嵌入(或缩小),负数使框架外凸(或扩大)。
同时请阅读 UIEdgeInsetsMake(_:_:_:_:)和UIEdgeInsetsZero
具体设定内嵌的数值需要应用UIEdgeInsetsMake(_:_:_:_:)或UIEdgeInsetsZero
UIEdgeInsetsMake(_:_:_:_:)
官当文档:
笔者翻译:
函数:UIEdgeInsetsMake(_:_:_:_:),为按钮或界面创建一个边界内嵌
声明:
func UIEdgeInsetsMake(
_ top: CGFloat, //顶端高度
_ left: CGFloat, //左端宽度
_ bottom: CGFloat, //底端高度
_ right: CGFloat) -> UIEdgeInsets //右端宽度
参数:
Top——对象的顶端内嵌
Left——对象的左端内嵌
Bottom——对象的底端内嵌
Right——对象的右端内嵌
返回值:按钮或界面的内嵌
描述:内嵌(insets)是在矩形外的边界,正值代表边界靠近矩形中心,负值代表边界远离矩形中心。
而若想将上下左右的内嵌区域都设为0,则可以直接设置为UIEdgeInsetsZero
UIEdgeInsetsZero
官当文档:
笔者翻译:
全局变量:UIEdgeInsetsZero
上下左右区域均为0的边界内嵌
声明:
const UIEdgeInsets UIEdgeInsetsZero;
总的来看,将可拉伸区域设置为1x1像素大小是表现最好的方案。
而文中提到的resizableImage(withCapInsets: resizingMode:)方法则可以直接控制拉伸时的填充模式,事实上,它只比resizableImage(withCapInsets:) 多了一个控制拉伸的填充模式参数。
resizableImage(withCapInsets:reizingMode:)
官当文档:
笔者翻译:
实例方法:resizableImage(withCapInsets: resizingMode:)
创建并返回一个设定有指定端盖内嵌(cap insets)及拉伸模式的图片对象
声明:
func resizableImage(withCapInsets capInsets: UIEdgeInsets,
resizingMode: UIIamgeResizingMode) -> UIImage
参数:
capInsets —— 端盖内嵌(cap insets)的数值
resizingMode —— 图像内部的拉伸方式
返回数值:
一个设定有指定端盖内嵌(cap insets)及拉伸方式的新图片对象
描述:
这个方法可以明确声明新图像对象的拉伸方式,除此之外,与同级的resizableImage(withCapInsets:) 完全一样。除非你想指定图像的拉伸模式,才可用它代替同级的resizableImage(withCapInsets:) 方法。
拉伸模式的变量类型是UIImageResizingMode
UIImageResizingMode
官当文档:(Swift语言)
笔者翻译:
枚举型:UIImageResizingMode,图像拉伸的具体伸缩模式
case title:平铺
图像在拉伸时采用平铺模式填充,也就是说,原始图像内部区域将会被重复平铺,以此填充新图像的大小。
case stretch:拉伸
图像在拉伸时采用拉伸模式填充,也就是说,原始图像内部区域将会被直接拉伸,以此填充新图像的大小。
注:用ObjC写的话,参数则为UIImageResizingModeTile、 UIImageResizingModeStretch
欢迎关注我的微信公众账号:用心玩手机