iOS frame與bounds區別詳解
轉自 http://blog.csdn.net/chenyufeng1991/article/details/51764303
在iOS的UI開發中,frame和bounds是兩個非常容易搞混的概念,而很多開發者在實際專案中也很少去區分,因此會導致出現一些意想不到的問題。本篇部落格以實際程式碼的方式來學習frame和bounds的使用。相關示例程式碼上傳至 https://github.com/chenyufeng1991/FrameAndBounds ,歡迎大家下載檢視。
(1)先來檢視一個介面中的容器self.view的frame和bounds的列印結果:下面的執行結果都在iPhone5s模擬器下進行。
- NSLog(@"self.view.frame = %@",NSStringFromCGRect(self.view.frame));
- NSLog(@"self.view.bounds = %@",NSStringFromCGRect(self.view.bounds));
。
在這裡我們可以看到,self.view的frame和bounds是一樣的。原點都是在左上角。長寬正好是整個螢幕的寬高。
(2)frame和bounds難道都是一樣的嗎?當然不是。現在我們對一個View做一個旋轉動畫。
- UIView *view01 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 50, 50)];
- view01.backgroundColor = [UIColor grayColor];
- [self.view addSubview:view01];
- NSLog(@"view01.frame = %@",NSStringFromCGRect(view01.frame));
-
NSLog(@"view01.bounds = %@",NSStringFromCGRect(view
- [UIView transitionWithView:view01 duration:2 options:0 animations:^{
- view01.transform = CGAffineTransformMakeRotation(M_PI_4);
- } completion:^(BOOL finished) {
- if (finished)
- {
- NSLog(@"view01.frame = %@",NSStringFromCGRect(view01.frame));
- NSLog(@"view01.bounds = %@",NSStringFromCGRect(view01.bounds));
- }
- }];
。
我們讓一個正方形旋轉90度,在動畫開始前和結束後分別列印frame和bounds,列印結果如下:
。
此時可以看到,在動畫開始前,frame和bounds也變得不一樣了。在旋轉動畫後,frame發生改變,bounds依然沒變。我現在告訴大家下面的結論:
-- frame的位置是根據父容器來計算的,正方形在動畫開始前的x=100,y=100是相對於self.view的座標系統而言的,從而確定當前檢視在父檢視中的位置。
-- bounds的x,y是根據自己的座標系統而言的。沒錯,每個view都有自己的座標系。以自己左上角點為座標原點。所以bounds的x,y預設為(0,0),除非呼叫setBounds方法;
-- frame的size不一定等於bounds的size,在旋轉後它們的size就不一樣了。
在旋轉前後,frame發生了較大的變化,其實旋轉後的frame變成了如下:
旋轉後:
。
旋轉前:
。
旋轉後,左上角origin的x,y發生了改變,size的height,width也 發生了改變,所以frame也就改變了。我們可以把frame理解為所佔區域,其實旋轉後的佔用區域是發生改變的。但是為什麼bounds沒有改變呢?
View在旋轉過程中,其實自己的座標系統並沒有發生改變,bounds中的origin只能通過setBounds方法修改。 根據英文中的意思,bounds就是邊界的意思,在旋轉過程中,View的邊界長短並沒有發生改變,所以bounds的size也就沒有改變。
所以我做個小小的別名:把frame理解為佔用區域,把bounds理解為邊界。
(3)我們把一個子View放到父View中,並且改變父View的bounds,來看看會發生什麼?
[objc] view plain copy print?- UIView *view02 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
- view02.backgroundColor = [UIColor colorWithWhite:0.851 alpha:1.000];
- [self.view addSubview:view02];
- UIView *view02_sub = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
- view02_sub.backgroundColor = [UIColor colorWithRed:1.000 green:0.908 blue:0.552 alpha:1.000];
- [view02 addSubview:view02_sub];
- [self printFrameAndBounds:view02 viewOfSub:view02_sub];
- [UIView animateWithDuration:1 animations:^{
- // setBounds 強制將自己座標系的左上角點改為(-30,-30)。那麼真正的原點(0,0)自然向右下角偏移(30,30);
- // 注意:setBounds中的(x,y)只改變自己的座標系統。子view的bounds和frame並不會改變。
- [view02 setBounds:CGRectMake(-30, -30, 200, 200)];
- } completion:^(BOOL finished) {
- [self printFrameAndBounds:view02 viewOfSub:view02_sub];
- }];
列印結果如下:
。
執行效果圖如下:
。
我們通過setBounds把父View的origin=(0,0)改為了(-30,-30), 發現子View向右下方發生了移動。我們來分析一下原因。
我們剛剛提到,setBounds可以改變自己View的座標系,父View強制把自己左上角的原點(0,0)座標改為了(-30,-30),但是對於子View.frame.origin=(0,0)來說,它的x,y沒有發生改變,仍然是(0,0), 由於左上角已經改為(-30,-30),所以真正的原點(0,0)向右下方移動,所以子View也就向右下方移動了。
做一個小小的總結:
-- setBounds中的(x,y)只改變自己的座標系統,子View的bounds和frame並不會改變;
-- setBounds是修改自己座標系的原點位置,進而影響到子View的顯示位置;
-- bounds改變位置時,改變的是子檢視的位置,自身沒有影響,其實就是改變了自身的座標系原點,預設原點在左上角。
(4)當父View的frame改變的時候,子View會發生什麼變化?
[objc] view plain copy print?- UIView *view02 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
- view02.backgroundColor = [UIColor colorWithWhite:0.851 alpha: