深入解析iOS應(yīng)用開發(fā)中九宮格視圖布局的相關(guān)計算方法
來看一個簡單的例子:
/*
* 總列數(shù)
*/
NSUInteger totalloc = 3;
/*
* View的寬高
*/
CGFloat shopW = 80;
CGFloat shopH = 100;
/*
* 每個View之間的間隔
*/
CGFloat margin = (self.view.frame.size.width - totalloc * shopW) / (totalloc + 1);
/*
* View的總個數(shù)
*/
NSUInteger count = 12;
/*
* 根據(jù)總個數(shù)使用總列數(shù)來除和取余獲取對應(yīng)的行和列
*/
NSUInteger loc = count / totalloc;
NSUInteger row = count % totalloc;
/*
* View的X和Y
*/
CGFloat shopX = margin + (margin + shopW) * row;
CGFloat shopY = margin + (margin + shopH) * loc;
/*
* 創(chuàng)建自定義View,設(shè)置背景顏色,添加到界面上去
*/
UIView *shopV = [[UIView alloc] initWithFrame:CGRectMake(shopX, shopY, shopW, shopH)];
shopV.backgroundColor = [UIColor lightGrayColor];
[self.shopView addSubview:shopV];
/*
* 創(chuàng)建UIImageView用于放置圖片,設(shè)置frame然后加到自定義的View上面
*/
UIImageView *imageV = [[UIImageView alloc] init];
imageV.frame = CGRectMake(0, 0, 80, 80);
[shopV addSubview:imageV];
/*
* 創(chuàng)建UILabel用于放置顯示文字,設(shè)置frame然后加到自定義的View上面
*/
UILabel *l = [[UILabel alloc] init];
l.frame = CGRectMake(0, 80, 80, 20);
l.textAlignment = NSTextAlignmentCenter;
[shopV addSubview:l];

根據(jù)例子可以看出設(shè)置九宮格的幾個要點步驟,下面我們再進一步深入探究尺寸和坐標(biāo)方面的相關(guān)計算。比如現(xiàn)在我們有一個UIView,和一個button,當(dāng)點擊button的時候,我們希望能在這個view上以九宮格的形式添加它的子view。
這里主要是記錄一下實現(xiàn)的思路,以后類似的問題都可以這樣思考。

如圖,我們首先要計算的應(yīng)該是horizalSpacing 和 verticalSpacing,因為拿到它們才可以計算坐標(biāo)值。
很明顯這個容器view的大小是固定的,每一個子view的大小也是固定的,所以可以拿到horizalSpacing和verticalSpacing的值,并且是通過動態(tài)計算,因為這樣才能保證,當(dāng)容器view或者子view的大小改變時,計算出的間距仍然是等大的。
這里首先要定義需要用到的常量:
#define ITEM_WIDTH 80.0
#define ITEM_HEIGHT 80.0
#define COLS_COUNT 3
#define ROWS_COUNT 3
當(dāng)點擊button的時候,會觸發(fā)addItemView的方法,就在這個方法里面計算水平和垂直間距:
- (IBAction)addItemView
{
CGFloat horizalSpacing = (self.bigView.bounds.size.width - COLS_COUNT * ITEM_WIDTH) / (COLS_COUNT - 1);
CGFloat verticalSpacing = (self.bigView.bounds.size.height - ROWS_COUNT * ITEM_HEIGHT) / (ROWS_COUNT - 1);
}
以horizalSpacing為例:
首先拿到容器view的總寬度:self.bigView.bounds.size.width
因為一行有三個item,每個item的寬度已知,所以可以計算出三個item占據(jù)的寬度:COLS_COUNT * ITEM_WIDTH
用總寬度減去三個item占據(jù)的寬度,剩下的空間就是總間距。
因為每一行有三個item,那么就會產(chǎn)生兩個間距。同理,一行有n個item,那么就會產(chǎn)生n-1個間距。
有了總間距,知道了共有多少個間距,那么每個間距占據(jù)多少就可以求出來,所以求出了horizalSpacing。
verticalSpacing同理。
有了水平和垂直item間的間距,我們就可以計算item的坐標(biāo):
第一個item: X1 = (ITEM_WIDTH + horizalSpacing) * 0, Y1 = 0
第二個item: X2 = (ITEM_WIDTH + horizalSpacing) * 1, Y1 = 0
第三個item: X3 = (ITEM_WIDTH + horizalSpacing) * 2, Y1 = 0
第四個item: X1 = (ITEM_WIDTH + horizalSpacing) * 0, Y2 = (ITEM_HEIGHT + verticalSpacing) * 1
第五個item: X2 = (ITEM_WIDTH + horizalSpacing) * 1, Y2 = (ITEM_HEIGHT + verticalSpacing) * 1
第六個item: X3 = (ITEM_WIDTH + horizalSpacing) * 2, Y2 = (ITEM_HEIGHT + verticalSpacing) * 1
...
可以看到,x和y坐標(biāo)都是有規(guī)律的:
x坐標(biāo)是通過
(ITEM_WIDTH + horizalSpacing) * index // 這里的index就是圖中item的編號
但是當(dāng)?shù)降谒膫€item的時候,又需要重復(fù)新一輪的index的值。
0 % 3 = 0, 1 % 3 = 1, 2 % 3 = 2
3 % 3 = 0, 4 % 3 = 1, 5 % 3 = 2
6 % 3 = 0, 7 % 3 = 1, 8 % 3 = 2
可以看到,是和上面進行的模運算是一個規(guī)律,所以我們就可以將代碼寫成這樣來計算x的值:
- (IBAction)addItemView
{
NSUInteger index = self.bigView.subviews.count; // 新增
CGFloat horizalSpacing = (self.bigView.bounds.size.width - COLS_COUNT * ITEM_WIDTH) / (COLS_COUNT - 1);
CGFloat verticalSpacing = (self.bigView.bounds.size.height - ROWS_COUNT * ITEM_HEIGHT) / (ROWS_COUNT - 1);
CGFloat x = (ITEM_WIDTH + horizalSpacing) * (index % COLS_COUNT); // 新增
}
在這里計算index并沒有采用單獨定義一個計數(shù)器,每次點擊后計數(shù)器加1這種方式,而是通過計算容器view的子view的個數(shù)。很明顯,第一次點擊前index = 0。(之后會定義view然后加到bigView中,這時bigView的子view就會+1了。)
同理,y值可以采用同樣的方法計算,不過要注意并非是進行取模計算,而是通過除法。(看一下每個item的序號并且和規(guī)律對應(yīng)上,就會發(fā)現(xiàn)是用除法。)
- (IBAction)addItemView
{
NSUInteger index = self.bigView.subviews.count;
CGFloat horizalSpacing = (self.bigView.bounds.size.width - COLS_COUNT * ITEM_WIDTH) / (COLS_COUNT - 1);
CGFloat verticalSpacing = (self.bigView.bounds.size.height - ROWS_COUNT * ITEM_HEIGHT) / (ROWS_COUNT - 1);
CGFloat x = (ITEM_WIDTH + horizalSpacing) * (index % COLS_COUNT);
CGFloat y = (ITEM_HEIGHT + verticalSpacing) * (index / COLS_COUNT); // 新增
}
拿到每次view的坐標(biāo),并且已知大小,就可以完成了。
- (IBAction)addItemView
{
NSUInteger index = self.bigView.subviews.count;
CGFloat horizalSpacing = (self.bigView.bounds.size.width - COLS_COUNT * ITEM_WIDTH) / (COLS_COUNT - 1);
CGFloat verticalSpacing = (self.bigView.bounds.size.height - ROWS_COUNT * ITEM_HEIGHT) / (ROWS_COUNT - 1);
CGFloat x = (ITEM_WIDTH + horizalSpacing) * (index % COLS_COUNT);
CGFloat y = (ITEM_HEIGHT + verticalSpacing) * (index / COLS_COUNT);
UIView *item = [[UIView alloc] initWithFrame:CGRectMake(x, y, ITEM_WIDTH, ITEM_HEIGHT)]; // 新增
item.backgroundColor = [UIColor redColor]; // 新增
[self.bigView addSubview:item]; // 新增
}
不僅僅是九宮格,無論改變item的大小還是bigView的大小,或者改變每一行每一列的item個數(shù),都可以很好的計算出每個item合適的大小和位置。
相關(guān)文章
iOS中修改UITextField占位符字體顏色的方法總結(jié)
這篇文章給大家分享了iOS中修改UITextField占位符字體顏色的三個方法,分別是使用attributedPlaceholder屬性、重寫drawPlaceholderInRect方法和修改UITextField內(nèi)部placeholderLaber的顏色,下面我們一起來看看詳細(xì)的方法介紹。2016-09-09
iOS開發(fā)UICollectionView實現(xiàn)拖拽效果
這篇文章主要為大家詳細(xì)介紹了iOS開發(fā)UICollectionView實現(xiàn)拖拽效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01
iOS tableView實現(xiàn)單選和多選的實例代碼
本篇文章主要介紹了iOS tableView實現(xiàn)單選和多選的實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07
在IOS中為什么使用多線程及多線程實現(xiàn)的三種方法
這篇文章給大家介紹在IOS中為什么使用多線程及多線程實現(xiàn)的三種方法,基本上使用這三種方法實現(xiàn)多線程(NSThread Grand Centeral Dispatch(GCD) NSOperation和NSOperationQueue),感興趣的朋友可以參考下本篇文章2015-11-11
iOS掃描二維碼實現(xiàn)手勢拉近拉遠(yuǎn)鏡頭
這篇文章主要為大家詳細(xì)介紹了iOS掃描二維碼實現(xiàn)手勢拉近拉遠(yuǎn)鏡頭,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04

