frame和bounds的區(qū)別

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


frame和bounds簡(jiǎn)介

先看一張圖:

image
  • 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));

效果圖:

image

輸出日志:

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í)顯示和輸出日志如下所示:

image
 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é)果如下:

image

分析:

可以看到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ì)改變。


image

結(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”的顯示位置。

參考

淺析frame與bounds

UIView.frame的騙局

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容