在iOS中我們會(huì)經(jīng)常遇到frame和bounds,這兩個(gè)概念很相似,但是也有區(qū)別。frame還好理解,但是bounds就比較容易迷惑人。我們通過實(shí)例來講解下bounds的概念,然后再看看bounds有哪些用途,這樣就可以徹底搞清楚bounds了。
frame和bounds簡(jiǎn)介
先看一張圖:

- frame: 該view在父view坐標(biāo)系統(tǒng)中的位置和大小。(參照點(diǎn)是,父親的坐標(biāo)系統(tǒng))
- bounds:該view在本地坐標(biāo)系統(tǒng)中的位置和大小。(參照點(diǎn)是,本地坐標(biāo)系統(tǒng),就相當(dāng)于ViewB自己的坐標(biāo)系統(tǒng),以0,0點(diǎn)為起點(diǎn))。
其實(shí)本地坐標(biāo)系統(tǒng)的關(guān)鍵就是要知道的它的原點(diǎn)(0,0)在父坐標(biāo)系統(tǒng)中的什么位置(這個(gè)位置是相對(duì)于父view的本地坐標(biāo)系統(tǒng)而言的,最終的父view就是UIWindow,它的本地坐標(biāo)系統(tǒng)原點(diǎn)就是屏幕的左上角了)。
通過修改view的bounds屬性可以修改本地坐標(biāo)系統(tǒng)的原點(diǎn)位置。
frame我相信大家都理解的比較清楚,但是bounds光是這么說估計(jì)大家都很迷糊,那么我們下面來看具體的實(shí)例。
bounds到底起什么作用
示例代碼:
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
view1.backgroundColor = [UIColor redColor];
[self.view addSubview:view1];//添加到self.view
NSLog(@"view1 frame:%@========view1 bounds:%@",NSStringFromCGRect(view1.frame),NSStringFromCGRect(view1.bounds));
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
view2.backgroundColor = [UIColor yellowColor];
[view1 addSubview:view2];//添加到view1上,[此時(shí)view1坐標(biāo)系左上角起點(diǎn)為(-20,-20)]
NSLog(@"view2 frame:%@========view2 bounds:%@",NSStringFromCGRect(view2.frame),NSStringFromCGRect(view2.bounds));
效果圖:

輸出日志:
view1 frame:{{100, 100}, {200, 200}}========view1 bounds:{{0, 0}, {200, 200}}
view2 frame:{{0, 0}, {100, 100}}========view2 bounds:{{0, 0}, {100, 100}}
這個(gè)是常規(guī)的場(chǎng)景,我相信大家都能理解。
下面我們來改變view1的bounds,代碼如下
[view1 setBounds:CGRectMake(-20, -20, 200, 200)];
此時(shí)顯示和輸出日志如下所示:

view1 frame:{{100, 100}, {200, 200}}========view1 bounds:{{-20, -20}, {200, 200}}
view2 frame:{{0, 0}, {100, 100}}========view2 bounds:{{0, 0}, {100, 100}}
分析
上面設(shè)置view1的bounds的代碼起到了讓view2的位置改變的作用。為何(-20,-20)的偏移量,卻可以讓view2向右下角移動(dòng)呢?
這是因?yàn)閟etBounds的作用是:強(qiáng)制將自己(view1)本地坐標(biāo)系的原點(diǎn)改為(-20,-20)。這個(gè)(-20,-20)是相對(duì)view1的父view(self.view)偏移的。也就是向左上角偏移。
那么在view1的坐標(biāo)系中(0,0)這個(gè)點(diǎn)是需要向右下各偏移20。
因?yàn)関iew1的subview(view2)的frame參照的坐標(biāo)系是父view(view1)的bounds設(shè)置的,而此時(shí)view2的frame設(shè)置為(0,0),就會(huì)導(dǎo)致view2向右下各偏移20。如上圖所示。
總結(jié)
所以,bounds的有這么一個(gè)特點(diǎn):
它是參考自己坐標(biāo)系,它可以修改自己坐標(biāo)系的原點(diǎn)位置,進(jìn)而影響到“子view”的顯示位置。
bounds使用場(chǎng)景
其實(shí)bounds我們一直在使用,就是我們使用scrollview的時(shí)候。
為什么我們滾動(dòng)scrollview可以看到超出顯示屏的內(nèi)容。就是因?yàn)閟crollview在不斷改變自己的bounds,從而改變scrollview上的子view的frame,讓他們的frame始終在最頂級(jí)view(window)的frame內(nèi)部,這樣我們就可以始終看到內(nèi)容了。
下面通過一個(gè)具體的例子來看看:
self.imageview = [[UIImageView alloc]initWithFrame:CGRectMake(100,0, 50, 1000)];
self.imageview.image = [UIImage imageNamed:@"1"];
self.imageview.contentMode = UIViewContentModeScaleAspectFill;
self.scrollview.contentSize = self.imageview.frame.size;
[self.scrollview addSubview:self.imageview];
在向上滾動(dòng)過程中,輸出scrollview的frame,bouns,contentoffset和子控件imageview的frame,bounds
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
NSLog(@"scrollview[contentoffset:%@---frame:%@------bounds:%@",NSStringFromCGPoint(scrollView.contentOffset), NSStringFromCGRect(self.scrollview.frame),NSStringFromCGRect(self.scrollview.bounds));
NSLog(@"imageview[frame:%@------bounds:%@",NSStringFromCGRect(self.imageview.frame),NSStringFromCGRect(self.imageview.bounds));
}
輸出結(jié)果如下:

分析:
可以看到imageview的frame和bounds還有scrollview的frame是沒有改變的。唯一在不斷改變的是scrollview的contentoffset和bounds,而且兩者完全相同。
結(jié)合上面我們講的知識(shí),就不難理解為什么scrollview要這么做了。
向上滾動(dòng)scrollview,我們就不斷增加scrollview的bounds的y值,也就是不斷把scrollview的本地坐標(biāo)系原點(diǎn)向下偏移(相對(duì)于scrollview的父view的坐標(biāo)系,y值越大,越向下偏移)。那么此時(shí)scrollview的子控件的frame設(shè)置的(0,0)就是不斷向上偏移
假設(shè)某一時(shí)刻scrollview的坐標(biāo)系原點(diǎn)為(0,100),那么scrollview的(0,0)位置就是相對(duì)于坐標(biāo)系原點(diǎn)向上偏移100的距離,設(shè)置scrollview的子控件的frame為(0,0),就是設(shè)置子控件左上角在scrollview中的(0,0)位置,那么子控件就會(huì)向上偏移100,你也就看到scrollview的內(nèi)容(子控件)向上滾動(dòng)的效果。
其實(shí)我們可以使用文章開始的例子來模式UIScrollview的滾動(dòng)效果,經(jīng)過上面的分析我們知道就是通過不斷增加UIScrollview的bounds的Y值,才可以出現(xiàn)滾動(dòng)效果從而顯示超出屏幕的內(nèi)容。
那么使用文章開頭的例子,我們可以不斷增加view1的bounds的y值,來看看是不是可以達(dá)到同樣的效果:view1不動(dòng),view2在不斷向上滾動(dòng)
代碼如下:
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 200, 100)];
view1.backgroundColor = [UIColor redColor];
[self.view addSubview:view1];//添加到self.view
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(20, 0, 100, 1000)];
view2.backgroundColor = [UIColor yellowColor];
[view1 addSubview:view2];//添加到view1上,[此時(shí)view1坐標(biāo)系左上角起點(diǎn)為(-20,-20)]
[UIView animateWithDuration:3.0 animations:^{
[view1 setBounds:CGRectMake(0, 1000, 200, 100)];
}];
運(yùn)行看看,可以發(fā)現(xiàn)view1固定不動(dòng),view2在不斷向上滾動(dòng),此時(shí)的view1就相當(dāng)于UIScrollview,而view2相當(dāng)于UIScrollview上面顯示的內(nèi)容,現(xiàn)在明白了嗎?
bouns大于frame的情況
假設(shè)設(shè)置了控件的bounds大于frame,那么此時(shí)會(huì)導(dǎo)致frame被撐大,frame的x,y,width,height都會(huì)改變。

結(jié)論
- 新的frame的size等于bound的size。
- 新的frame.x = 舊frame.x - (bounds.size.witdh - 舊frame.size.width)/2
- 新的frame.y = 舊frame.y - (bounds.size.height - 舊frame.size.height)/2
bound的改變會(huì)累加
假設(shè)view1上面添加了view2,view2上面添加了view3。三個(gè)view的size都是(100,100)。
我們?cè)O(shè)置如下:
view1.bound = (0,100,100,100)
view2.bound = (0,100,100,100)
那么此時(shí)view3.frame = (0,0,100,100),view3會(huì)相對(duì)于原來沒有設(shè)置view1、view2的bound時(shí)的位置向上偏移200。
總結(jié)
- frame是參考父view的坐標(biāo)系來設(shè)置自己左上角的位置。
- 設(shè)置bounds可以修改自己坐標(biāo)系的原點(diǎn)位置,進(jìn)而影響到其“子view”的顯示位置。