导语:
有时候对一个图片进行常规的缩放达不到我们想要的效果,比如聊天气泡的大小、带边框的按钮背景。通常我们会设置某个偏移值对图片进行拉伸来实现我们想要的效果。iOS6以后有两条相似的API可以解决这一问题,下文简称带模式的缩放和不带模式的缩放。
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets;
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode;
下面是官方文档对API的解释:
Each inset defines the potion of the image that does not stretch in the given dimension. The regions inside an image’s top and bottom insets maintain a fixed height, and the areas inside the left and right insets maintain a fixed width. Figure 2 shows how each part of a nine-part image stretches as the image itself is stretched to fill the available space. The corners of the image do not change size because they are inside both a horizontal and vertical inset.
也就是说会传入一个UIEdgeInsets
类型的结构体将UIImage
分为9个(也有可能是2个)部分,并对其中间部分和四个边进行缩放,但是四个角会保持不变。
下面分别介绍这两条API。
不带模式的缩放
缩放模式有两种,分别是UIImageResizingModeTile
平铺和UIImageResizingModeStretch
拉伸。如果不指定缩放模式,则会根据传入UIEdgeInsets
类型的结构体的不同而进行不同的缩放。
原文是这么说的:
iOS uses different rendering techniques, with different performance characteristics, depending on the size of each resizable area in the image:
If resizable areas have a width or height of 1 pixel—that is, a horizontally resizable area is 1 pixel wide, a vertically resizable area is 1 pixel tall, or the center region of the image is 1 x 1 pixel—iOS draws the image by stretching the 1-pixel region. This mode provides the fastest performance (for nonzero cap insets).
If resizable areas have a width or height greater than 1 pixel, iOS draws the image by tiling the region. This mode provides reduced performance, but can be useful for images with textured (rather than solid-color) content in their resizable areas.
If the entire image is resizable—that is, the capInsets parameter is UIEdgeInsetsZero—and its size is greater than 1 x 1 pixel, iOS draws the image by tiling the entire image. This mode is faster than the tiling mode for nonzero cap insets.
也就是说,
- 如果中间部分边长都小于或等于1,这种情况下可变部分从上往下、从左至右按一个像素偏移值按照拉伸模式来放大。若中间部分有一边大于1,则大于1的那边按平铺模式缩放,小于1的那边以一个像素的默认偏移值按拉伸模式缩放。
- 如果中间部分边长大于1x1;在这种情况下可变部分按照平铺模式来放大。
- 如果中间部分大小等于图片的大小,并且图片大小大于1x1,也就是说传入的参数为
UIEdgeInsetsZero
,在这种情况下可变部分按照平铺模式来放大。
下面用一张对称的图片来测试,图片大小是90x90,imageView
大小为180x180,上面是测试图下面是原图。
中间部分大小为0的情况,传入的参数为:UIEdgeInsetsMake(image.size.height*0.5, image.size.width*0.5, image.size.height*0.5, image.size.width*0.5)
中间部分叠加(小于0)的情况,传入的参数为:UIEdgeInsetsMake(image.size.height*0.5, image.size.width*0.5, image.size.height*0.5+20, image.size.width*0.5+20)
中间部分边长均小于1的情况,传入的参数为:UIEdgeInsetsMake(image.size.height*0.5, image.size.width*0.5, image.size.height*0.5-0.5, image.size.width*0.5-0.5)
中间部分边长均大于1的情况,传入的参数为:UIEdgeInsetsMake(image.size.height*0.3, image.size.width*0.3, image.size.height*0.3, image.size.width*0.3)
中间部分等于图片大小的情况,传入的参数为:UIEdgeInsetsZero
带模式的缩放
这种缩放方式出现在iOS6+,官方说明如下:
This method is exactly the same as its counterpart resizableImageWithCapInsets: except that the resizing mode of the new image object can be explicitly declared. You should only call this method in place of its counterpart if you specifically want your image to be resized with the UIImageResizingModeStretch resizing mode.
意思就是这种缩放方式和前面的差不多,除非你一定要用拉伸的方式来放大图片,否则还是建议你使用不带模式的方式来处理你的图片。
拉伸模式,传入的参数为:UIEdgeInsetsMake(image.size.height*0.3, image.size.width*0.3, image.size.height*0.3, image.size.width*0.3)
平铺模式,传入的参数为:UIEdgeInsetsMake(image.size.height*0.3, image.size.width*0.3, image.size.height*0.3, image.size.width*0.3)
这两种方法都不会改变原图,而是返回一张新的图片。其实在像素为1的情况下也看不出是平铺模式还是拉伸模式(性能上拉伸模式好得多),如果是纯色背景两种模式区别也不大。anyway,知道总比不知道要强。