iOS開發筆記(四):frame與bounds的區別詳解

卡布達巨人發表於2018-01-15

相信大家學習iOS檢視部分的時候,跟它倆沒少糾纏,尤其是bounds很多朋友都糊了,bounds確實比較難理解。這兩個概念很重要,因為它們是奠定整個檢視層次結構的基礎。所以我們需要了解的透徹一點。原始碼

首先,我們來看一下iOS特有的座標系,在iOS座標系中以左上角為座標原點,往右為X正方向,往下是Y正方向如下圖:

iOS座標系

bounds和frame都是屬於CGRect型別的結構體,系統的定義如下,包含一個CGPoint(起點)和一個CGSize(尺寸)子結構體。

struct CGRect { 
CGPoint origin;
CGSize size;

};
複製程式碼

origin決定了view的起點,size決定View的尺寸。

1.frame

frame是每個view必備的屬性,表示view在父view座標系統中的位置和大小,參照點是父檢視的座標系統。

示例程式碼:

UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 300, 300)];
[viewA setBackgroundColor:[UIColor blueColor]];
[self.view addSubview:viewA];
NSLog(@"viewA - %@",NSStringFromCGRect(viewA.frame));
UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
[viewB setBackgroundColor:[UIColor yellowColor]];
[viewA addSubview:viewB];
NSLog(@"viewB - %@",NSStringFromCGRect(viewB.frame));
UIView *viewC = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[viewC setBackgroundColor:[UIColor redColor]];
[self.view addSubview:viewC];
NSLog(@"viewC - %@",NSStringFromCGRect(viewC.frame));
複製程式碼

列印結果:

2018-01-14 21:35:16.196389+0800 frame &
bounds[1485:121325] viewA - {{50, 50
}, {300, 300
}
}2018-01-14 21:35:16.196647+0800 frame &
bounds[1485:121325] viewB - {{50, 50
}, {200, 200
}
}2018-01-14 21:35:16.196802+0800 frame &
bounds[1485:121325] viewC - {{100, 100
}, {200, 200
}
}複製程式碼

效果圖:

frame

以上可以看出,viewB和viewC的起點重合,但是從列印結果來看,viewB的起點為(50,50),而viewCde起點為(100,100)。原因就是frame中的位置是以父檢視的座標系為標準來確定當前檢視的位置,viewB的父檢視為viewA,viewC的父檢視為self.view,而由於viewA的起點為(50,50),所以viewB與viewC起點才會重合。

2.bounds

bounds也是每個view都有的屬性,這個屬性我們一般不進行設定,表示view在本地座標系統中的位置和大小。參照點是本地座標系統。如果我們對上例列印bounds,將會得到以下結果:

2018-01-14 22:03:44.385207+0800 frame &
bounds[1635:140821] viewA - {{0, 0
}, {300, 300
}
}2018-01-14 22:03:44.385482+0800 frame &
bounds[1635:140821] viewB - {{0, 0
}, {200, 200
}
}2018-01-14 22:03:44.385646+0800 frame &
bounds[1635:140821] viewC - {{0, 0
}, {100, 100
}
}複製程式碼

因為我們並沒有設定bounds值,那麼,bounds到底有什麼作用呢。這裡強調,每個檢視都有自己的座標系,且這個座標系預設以自身的左上角為座標原點,所有子檢視以這個座標系的原點為基準點。bounds的位置代表的是子檢視看待當前檢視左上角的位置,bounds的大小代表當前檢視的大小。原則如下:

  • 更改bounds中的位置對於當前檢視沒有影響,相當於更改了當前檢視的座標系,對於子檢視來說當前檢視的左上角已經不再是(0,0), 而是改變後的座標,座標系改了,那麼所有子檢視的位置也會跟著改變。
  • 更改bounds的大小,bounds的大小代表當前檢視的長和寬,修改長寬後,中心點繼續保持不變, 長寬進行改變,通過bounds修改長寬看起來就像是以中心點為基準點對長寬兩邊同時進行縮放。

以下給出例子詳細討論。

3.兩者的區別

3.1 origin的區別

如下圖:

frame&<br />bounds 1″ class=”lazyload” data-height=”527″ src=”https://user-gold-cdn.xitu.io/2018/1/15/160f59848e5ce396?imageView2/0/w/1280/h/960/ignore-error/1″ data-width=”700″><figcaption></figcaption></figure>
</p>
<p>此時,如果我們把ViewA的bounds改為(0,100),結果如下:</p>
</p>
<figure><img alt=bounds 2″ class=”lazyload” data-height=”524″ src=”https://user-gold-cdn.xitu.io/2018/1/15/160f5984d117acd7?imageView2/0/w/1280/h/960/ignore-error/1″ data-width=”700″>

我們始終要清楚,bounds的位置代表的是子檢視看待當前檢視左上角的位置。bounds遵守的原則一中,更改bounds中的位置對於當前檢視(ViewA)沒有影響,相當於更改了ViewA的座標系,但是子檢視(ViewB)不同,對於ViewB來說ViewA的左上角已經不再是(0,0), 而是(0,100),所以對於ViewB來說,ViewA座標系的原點其實是在紅色箭頭所指處的上方100處,而此時ViewB的frame.origin為(200,100),所以ViewB的上邊與ViewA上邊重合。

如果我們更改ViewA的bounds為(200,0),同理(可以自己思考試試),結果如下:

frame&<br />bounds 3″ class=”lazyload” data-height=”524″ src=”https://user-gold-cdn.xitu.io/2018/1/15/160f59848beb0e02?imageView2/0/w/1280/h/960/ignore-error/1″ data-width=”700″><figcaption></figcaption></figure>
</p>
<h3 class=3.2 size的區別

frame的size直接決定了view的大小,而bounds的size修改後,view的中心點不變,長寬以中心點進行縮放。

如下例:

UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 240)];
[viewA setBackgroundColor:[UIColor grayColor]];
[self.view addSubview:viewA];
UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(100, 50, 160, 120)];
[viewB setBackgroundColor:[UIColor blueColor]];
[viewA addSubview:viewB];
//viewB設定size(320,160)[viewB setBounds:CGRectMake(0, 0, 320, 240)];
複製程式碼

結果如下:

未設定size
已設定size

第二個圖為設定了size之後的結果,viewB左上點距離viewA顯然不為(100,50),而是進行了基於viewB檢視中心點的縮放操作。

4.總結

  • frame不管對於位置還是大小,改變的都是自己本身。
  • frame的位置是以父檢視的座標系為參照,從而確定當前檢視在父檢視中的位置。
  • frame的大小改變時,當前檢視的左上角位置不會發生改變,只是大小發生改變。
  • bounds改變位置時,改變的是子檢視的位置,自身沒有影響;其實就是改變了本身的座標系原點,預設本身座標系的原點是左上角。
  • bounds的大小改變時,當前檢視的中心點不會發生改變,當前檢視的大小發生改變,看起來效果就想縮放一樣。

5.參考

來源:https://juejin.im/post/5a5b8b41f265da3e4c07c0bc

相關文章