1. 故事背景
蘋果公司為iOS開發者提供了以下的方法用於處理圖片的拉伸問題
1 2 |
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode //為行文方便,之後簡稱該方法為拉伸方法 |
但在實際使用過程中,我發現自己對該方法的理解不夠深入,所以今天特地編寫了一些程式碼來探析該方法!
好了,廢話不多說,下面我們就開始探析該方法的奧妙吧!
2. 方法介紹和說明
1 2 3 4 5 6 7 8 9 10 |
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode //該方法返回的是UIImage型別的物件,即返回經該方法拉伸後的影像 //傳入的第一個引數capInsets是UIEdgeInsets型別的資料,即原始影像要被保護的區域 //這個引數是一個結構體,定義如下 //typedef struct { CGFloat top, left , bottom, right ; } UIEdgeInsets; //該引數的意思是被保護的區域到原始影像外輪廓的上部,左部,底部,右部的直線距離,參考圖2.1 //傳入的第二個引數resizingMode是UIImageResizingMode類似的資料,即影像拉伸時選用的拉伸模式, //這個引數是一個列舉型別,有以下兩種方式 //UIImageResizingModeTile, 平鋪 //UIImageResizingModeStretch, 拉伸 |
圖2.1 capInsets 引數示意圖.png
3. 設計實驗方法
實驗物件
Image物件尺寸為60*
128(為行文方便,之後簡稱為原始影像,圖3.1)
ImageView物件尺寸為180*
384(為行文方便,之後簡稱為相框)
圖3.1 原始影像.png
實驗方法
- 對原始影像使用拉伸方法並輸入不同的引數
- 將拉伸後的影像放入相框,觀察其拉伸效果
測試軟體的介面設計
介面設計如圖3.2
正上方為原始影像視窗,用於顯示原始影像的效果
左下方為測試影像視窗,用於顯示測試狀況的效果
右下方為對比影像視窗,用於顯示預設狀況的效果
圖3.2 測試軟體的介面設計.png
4.實驗分析
4.1 拉伸模式
resizingMode引數為UIImageResizingModeStretch
4.1.1.capInsets引數為UIEdgeInsetsMake(0, 0, 0, 0)時
當我們向拉伸方法傳入該組引數時,代表我們未對原始影像的任何區域進行保護.其拉伸效果如圖4.1.1
在該種情況下,我們發現原始影像按比例放大了3倍,因此我們將該情況當做拉伸模式下的預設狀況
在之後的實驗中,我們將該種狀況當做參考物件,顯示在介面的右下角
圖4.1.1 測試結果1.png
4.1.2.capInsets引數為UIEdgeInsetsMake(42, 0, 0, 0)時
當我們向拉伸方法傳入該組引數時,代表我們對原始影像上部的三分之一進行保護(即紅色方塊區域).其拉伸效果如圖4.1.2
在該種情況下,我們可以發現拉伸後的影像中:
- 原始影像中受保護的區域(即紅色方塊區域)在Y軸方向保持了原比例,但在X軸方向進行了拉伸
- 原始影像中未受保護的區域,直接按比例進行了拉伸
圖4.1.2 測試結果2.png
4.1.3.capInsets引數為UIEdgeInsetsMake(0,20, 0, 0)時
當我們向拉伸方法傳入該組引數時,代表我們對原始影像左部的三分之一進行保護(即紅色方塊區域).其拉伸效果如圖4.1.3
在該種情況下,我們可以發現拉伸後的影像中:
- 原始影像中受保護的區域(即紅色方塊區域)在X軸方向保持了原比例,但在Y軸方向進行了拉伸
- 原始影像中未受保護的區域,直接按比例進行了拉伸
圖4.1.3 測試結果3.png
4.1.4.capInsets引數為UIEdgeInsetsMake(42, 20, 42, 20)時
當我們向拉伸方法傳入該組引數時,代表我們對原始影像除數字5以外的區域進行保護(即兩個紅色方塊圍起來的區域).其拉伸效果如圖4.1.4
在該種情況下,我們可以發現拉伸後的影像中:
- 在X軸上,由於1被左邊和上邊的設定保護,3被右邊和上邊的設定保護,所以只能用中間的2來拉伸,同理最底下的7,8,9
- 在Y軸上,由於1被左邊和上邊的設定保護,7被左邊和下邊的設定保護,所以只能用中間的4來拉伸,同理最底下的3,6,9
- 由於5沒有被保護,所以在整個剩餘的空間中,用5進行拉伸填充
圖4.1.4 測試結果4.png
4.2選擇平鋪模式
resizingMode引數為UIImageResizingModeTile
4.2.1.capInsets引數為UIEdgeInsetsMake(0, 0, 0, 0)時
當我們向拉伸方法傳入該組引數時,代表我們未對原始影像的任何區域進行保護.其平鋪效果如圖4.2.1
在該種情況下,我們發現原始影像按比例填充了相框,因此我們將該情況當做拉伸模式下的預設狀況
在之後的實驗中,我們將該種狀況當做參考物件,顯示在介面的右下角
圖4.2.1 測試結果1.png
4.2.2.capInsets引數為UIEdgeInsetsMake(42, 0, 0, 0)時
當我們向拉伸方法傳入該組引數時,代表我們對原始影像上部的三分之一進行保護(即紅色方塊區域).其平鋪效果如圖4.2.2
在該種情況下,我們可以發現拉伸後的影像中:
- 原始影像中受保護的區域(即紅色方塊區域)在Y軸方向保持了原比例,但在X軸方向進行了平鋪填充
- 原始影像中未受保護的區域,直接按比例進行了平鋪,但不包含被保護的區域(注意觀察藍色箭頭所指的區域)
Paste_Image.png
4.2.3.capInsets引數為UIEdgeInsetsMake(0,20, 0, 0)時
當我們向拉伸方法傳入該組引數時,代表我們對原始影像左部的三分之一進行保護(即紅色方塊區域).其平鋪效果如圖4.2.3
在該種情況下,我們可以發現拉伸後的影像中:
- 原始影像中受保護的區域(即紅色方塊區域)在X軸方向保持了原比例,但在Y軸方向進行了平鋪填充
- 原始影像中未受保護的區域,直接按比例進行了平鋪,但不包含被保護的區域(注意觀察藍色箭頭所指的區域)
圖4.2.3 測試結果3.png
4.2.4.capInsets引數為UIEdgeInsetsMake(42, 20, 42, 20)時
當我們向拉伸方法傳入該組引數時,代表我們對原始影像除數字5以外的區域進行保護(即兩個紅色方塊圍起來的區域).其拉伸效果如圖4.2.4
在該種情況下,我們可以發現拉伸後的影像中:
- 在X軸上,由於1被左邊和上邊的設定保護,3被右邊和上邊的設定保護,所以只能用中間的2來平鋪,同理最底下的7,8,9
- 在Y軸上,由於1被左邊和上邊的設定保護,7被左邊和下邊的設定保護,所以只能用中間的4來平鋪,同理最底下的3,6,9
- 由於5沒有被保護,所以在整個剩餘的空間中,用5進行平鋪填充
圖4.2.4 測試結果4.png
5. 結論和建議
通過8組實驗資料可以觀察出拉伸方法在平鋪模式和拉伸模式下的變化過程和主要區別,由此我們可知:
- 對原始圖形使用拉伸方法且在四周增加保護區域後,能保證原始圖形的四個角不失真,但其餘部分的變化細節則有不同
- 如果原始影像的外輪廓不平整的話,使用拉伸方式會讓外輪廓的不平整度放大,使用平鋪方式應該能減小這種情況
6. 附錄-程式碼
為了縮短程式碼的長度,我使用了Storyboard搭建軟體介面,想重現實驗的朋友可以自行構建介面,具體的引數我在文章和附錄中進行了簡要說明,我相信聰明的你一定可以搞定!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView1; @property (weak, nonatomic) IBOutlet UIImageView *imageView2; @property (weak, nonatomic) IBOutlet UIImageView *imageView3; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //--imageView1的相關內容------------------------------------------------------------------------------------ //相框大小為60 * 128 圖片尺寸為60 * 128 //讀取圖片 UIImage *testImage1 = [UIImage imageNamed:@"123456789"]; testImage1 = [testImage1 resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0) resizingMode:UIImageResizingModeStretch]; self.imageView1.image = testImage1; //---imageView2的相關內容----------------------------------------------------------------------------------- //相框為180 * 384 圖片尺寸為60 * 128 相框大小為原始圖片的3倍 //讀取圖片 UIImage *testImage2 = [UIImage imageNamed:@"123456789"]; /***********************************************/ //方法1 resizableImageWithCapInsets:預設是平鋪 //方法2 resizableImageWithCapInsets: resizingMode: 方法 // UIImageResizingModeTile, 平鋪 //平鋪的概念是保證原影像大小不變,將新影像填充滿 //testImage2 = [testImage2 resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0) resizingMode:UIImageResizingModeTile]; //將上部的三分之一"保護",然後進行顯示 //這代表新影像中,上部的三分之一和原影像一樣,而其餘部分的填充不會使用原影像上部的三分之一 // testImage2 = [testImage2 resizableImageWithCapInsets:UIEdgeInsetsMake(42, 0, 0, 0) resizingMode:UIImageResizingModeTile]; //將左部的三分之一"保護",然後進行顯示 //這代表新影像中,上部的三分之一和原影像一樣,而其餘部分的填充不會使用原影像上部的三分之一 // testImage2 = [testImage2 resizableImageWithCapInsets:UIEdgeInsetsMake(0,20, 0, 0) resizingMode:UIImageResizingModeTile]; //將四周進行保護後 //在X軸上,由於1被左邊的設定保護,3被右邊的設定保護,所以中間只能用2來平鋪,同理,7和9之間的8 //在Y軸上,由於1被上邊的設定保護,7被下邊的設定保護,所以中間只能用4來平鋪,同理,3和9之間的6 //由於5沒有被保護,所以在整個空間中,用5進行平鋪來填充剩餘的區域 // testImage2 = [testImage2 resizableImageWithCapInsets:UIEdgeInsetsMake(42, 20, 42, 20) resizingMode:UIImageResizingModeTile]; /***********************************************/ //resizableImageWithCapInsets: resizingMode: 方法 // UIImageResizingModeStretch, 拉伸 // 拉伸的概念是直接按比例將圖片放大到與相框尺寸相同的影像, //testImage2 = [testImage2 resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0) resizingMode:UIImageResizingModeStretch]; //將上部的三分之一"保護",然後進行顯示 //保證原影像上部的三分之一在Y軸上不被拉伸,其餘部分按剩餘比例拉伸 //testImage2 = [testImage2 resizableImageWithCapInsets:UIEdgeInsetsMake(42, 0, 0, 0) resizingMode:UIImageResizingModeStretch]; //將左部的三分之一"保護",然後進行顯示 //保證原影像左部的三分之一在Y軸上不被拉伸,其餘部分按剩餘比例拉伸 //testImage2 = [testImage2 resizableImageWithCapInsets:UIEdgeInsetsMake(0, 20, 0, 0) resizingMode:UIImageResizingModeStretch]; //將四周進行保護後 //在X軸上,由於1被左邊的設定保護,3被右邊的設定保護,所以中間只能用2來拉伸,同理,7和9之間的8 //在Y軸上,由於1被上邊的設定保護,7被下邊的設定保護,所以中間只能用4來拉伸,同理,3和9之間的6 //由於5沒有被保護,所以在整個空間中,用5進行拉伸來填充剩餘的區域 //testImage2 = [testImage2 resizableImageWithCapInsets:UIEdgeInsetsMake(42, 20, 42, 20) resizingMode:UIImageResizingModeStretch]; //將圖片新增到相框 self.imageView2.image = testImage2; //-----imageView3的相關內容---------------------------------------------------------------------------------- //讀取圖片 UIImage *testImage3 = [UIImage imageNamed:@"123456789"]; /***********************************************/ //resizableImageWithCapInsets預設是平鋪 //resizableImageWithCapInsets預設情況對比圖 //testImage3 = [testImage3 resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0) resizingMode:UIImageResizingModeTile]; /***********************************************/ //resizableImageWithCapInsets: resizingMode: 方法 // UIImageResizingModeTile, 平鋪 (已經測試過了,) // UIImageResizingModeStretch, 拉伸 //testImage3 = [testImage3 resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0) resizingMode:UIImageResizingModeStretch]; /***********************************************/ //將圖片新增到相框 self.imageView3.image = testImage3; // Do any additional setup after loading the view, typically from a nib. } @end |