原連結:http://www.jianshu.com/p/964313cfbdaa
原作者:西木柚子
僅供我個人收藏學習,原博主如不同意請聯絡qq651263878進行刪除,在此表示感謝以及歉意。
在iOS中我們會經常遇到frame和bounds,這兩個概念很相似,但是也有區別。frame還好理解,但是bounds就比較容易迷惑人。我們通過例項來講解下bounds的概念,然後再看看bounds有哪些用途,這樣就可以徹底搞清楚bounds了。
frame和bounds簡介
先看一張圖:
frame: 該view在父view座標系統中的位置和大小。(參照點是,父親的座標系統)
bounds:該view在本地座標系統中的位置和大小。(參照點是,本地座標系統,就相當於ViewB自己的座標系統,以0,0點為起點)。
其實本地座標系統的關鍵就是要知道的它的原點(0,0)在父座標系統中的什麼位置(這個位置是相對於父view的本地座標系統而言的,最終的父view就是UIWindow,它的本地座標系統原點就是螢幕的左上角了)。
通過修改view的bounds屬性可以修改本地座標系統的原點位置。
frame我相信大家都理解的比較清楚,但是bounds光是這麼說估計大家都很迷糊,那麼我們下面來看具體的例項。
bounds到底起什麼作用
示例程式碼:
UIView*view1 = [[UIViewalloc] initWithFrame:CGRectMake(200,200,100,100)]; view1.backgroundColor = [UIColorredColor]; [self.view addSubview:view1];//新增到self.viewNSLog(@"view1 frame:%@========view1 bounds:%@",NSStringFromCGRect(view1.frame),NSStringFromCGRect(view1.bounds));UIView*view2 = [[UIViewalloc] initWithFrame:CGRectMake(0,0,100,100)]; view2.backgroundColor = [UIColoryellowColor]; [view1 addSubview:view2];//新增到view1上,[此時view1座標系左上角起點為(-20,-20)]NSLog(@"view2 frame:%@========view2 bounds:%@",NSStringFromCGRect(view2.frame),NSStringFromCGRect(view2.bounds));
效果圖:
image
輸出日誌:
image
這個是常規的場景,我相信大家都能理解。
下面我們來改變view1的bounds,程式碼如下
[view1 setBounds:CGRectMake(-20,-20,200,200)];
此時顯示和輸出日誌如下所示:
image
image
分析
上面設定view1的bounds的程式碼起到了讓view2的位置改變的作用。為何(-20,-20)的偏移量,卻可以讓view2向右下角移動呢?
這是因為setBounds的作用是:強制將自己(view1)本地座標系的原點改為(-20,-20)。這個(-20,-20)是相對view1的父view(self.view)偏移的。也就是向左上角偏移。
那麼在view1的座標系中(0,0)這個點是需要向右下各偏移20。
因為view1的subview(view2)的frame參照的座標系是父view(view1)的bounds設定的,而此時view2的frame設定為(0,0),就會導致view2向右下各偏移20。如上圖所示。
總結
所以,bounds的有這麼一個特點:
它是參考自己座標系,它可以修改自己座標系的原點位置,進而影響到“子view”的顯示位置。
bounds使用場景
其實bounds我們一直在使用,就是我們使用scrollview的時候。
為什麼我們滾動scrollview可以看到超出螢幕的內容。就是因為scrollview在不斷改變自己的bounds,從而改變scrollview上的子view的frame,讓他們的frame始終在最頂級view(window)的frame內部,這樣我們就可以始終看到內容了。
下面通過一個具體的例子來看看:
self.imageview = [[UIImageViewalloc]initWithFrame:CGRectMake(100,0,50,1000)];self.imageview.image = [UIImageimageNamed:@"1"];self.imageview.contentMode =UIViewContentModeScaleAspectFill;self.scrollview.contentSize =self.imageview.frame.size; [self.scrollview addSubview:self.imageview];
在向上滾動過程中,輸出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));}
輸出結果如下:
image
分析:
可以看到imageview的frame和bounds還有scrollview的frame是沒有改變的。唯一在不斷改變的是scrollview的contentoffset和bounds,而且兩者完全相同。
結合上面我們講的知識,就不難理解為什麼scrollview要這麼做了。
向上滾動scrollview,我們就不斷增加scrollview的bounds的y值,也就是不斷把scrollview的本地座標系原點向下偏移(相對於scrollview的父view的座標系,y值越大,越向下偏移)。那麼此時scrollview的子控制元件的frame設定的(0,0)就是不斷向上偏移
假設某一時刻scrollview的座標系原點為(0,100),那麼scrollview的(0,0)位置就是相對於座標系原點向上偏移100的距離,設定scrollview的子控制元件的frame為(0,0),就是設定子控制元件左上角在scrollview中的(0,0)位置,那麼子控制元件就會向上偏移100,你也就看到scrollview的內容(子控制元件)向上滾動的效果。
其實我們可以使用文章開始的例子來模式UIScrollview的滾動效果,經過上面的分析我們知道就是通過不斷增加UIScrollview的bounds的Y值,才可以出現滾動效果從而顯示超出螢幕的內容。
那麼使用文章開頭的例子,我們可以不斷增加view1的bounds的y值,來看看是不是可以達到同樣的效果:view1不動,view2在不斷向上滾動
程式碼如下:
UIView*view1 = [[UIViewalloc] initWithFrame:CGRectMake(100,200,200,100)]; view1.backgroundColor = [UIColorredColor]; [self.view addSubview:view1];//新增到self.viewUIView*view2 = [[UIViewalloc] initWithFrame:CGRectMake(20,0,100,1000)]; view2.backgroundColor = [UIColoryellowColor]; [view1 addSubview:view2];//新增到view1上,[此時view1座標系左上角起點為(-20,-20)][UIViewanimateWithDuration:3.0animations:^{ [view1 setBounds:CGRectMake(0,1000,200,100)]; }];
執行看看,可以發現view1固定不動,view2在不斷向上滾動,此時的view1就相當於UIScrollview,而view2相當於UIScrollview上面顯示的內容,現在明白了嗎?
bouns大於frame的情況
假設設定了控制元件的bounds大於frame,那麼此時會導致frame被撐大,frame的x,y,width,height都會改變。
image
結論
新的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的改變會累加
假設view1上面新增了view2,view2上面新增了view3。三個view的size都是(100,100)。
我們設定如下:
view1.bound = (0,100,100,100)
view2.bound = (0,100,100,100)
那麼此時view3.frame = (0,0,100,100),view3會相對於原來沒有設定view1、view2的bound時的位置向上偏移200。
總結
frame是參考父view的座標系來設定自己左上角的位置。
設定bounds可以修改自己座標系的原點位置,進而影響到其“子view”的顯示位置。