1. 程式人生 > >iOS frame與bounds區別詳解

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模擬器下進行。

[objc] view plain copy  print?在CODE上檢視程式碼片派生到我的程式碼片
  1. NSLog(@"self.view.frame = %@",NSStringFromCGRect(self.view.frame));  
  2. NSLog(@"self.view.bounds = %@",NSStringFromCGRect(self.view.bounds));  

在這裡我們可以看到,self.view的frame和bounds是一樣的。原點都是在左上角。長寬正好是整個螢幕的寬高。

(2)frame和bounds難道都是一樣的嗎?當然不是。現在我們對一個View做一個旋轉動畫。

[objc] view plain copy  print?在CODE上檢視程式碼片派生到我的程式碼片
  1. UIView *view01 = [[UIView alloc] initWithFrame:CGRectMake(1001005050)];  
  2. view01.backgroundColor = [UIColor grayColor];  
  3. [self.view addSubview:view01];  
  4. NSLog(@"view01.frame = %@",NSStringFromCGRect(view01.frame));  
  5. NSLog(@"view01.bounds = %@",NSStringFromCGRect(view
    01.bounds));  
  6. [UIView transitionWithView:view01 duration:2 options:0 animations:^{  
  7.     view01.transform = CGAffineTransformMakeRotation(M_PI_4);  
  8. } completion:^(BOOL finished) {  
  9.     if (finished)  
  10.     {  
  11.         NSLog(@"view01.frame = %@",NSStringFromCGRect(view01.frame));  
  12.         NSLog(@"view01.bounds = %@",NSStringFromCGRect(view01.bounds));  
  13.     }  
  14. }];  
動畫效果如下:

我們讓一個正方形旋轉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?在CODE上檢視程式碼片派生到我的程式碼片
  1. UIView *view02 = [[UIView alloc] initWithFrame:CGRectMake(100100200200)];  
  2.    view02.backgroundColor = [UIColor colorWithWhite:0.851 alpha:1.000];  
  3.    [self.view addSubview:view02];  
  4.    UIView *view02_sub = [[UIView alloc] initWithFrame:CGRectMake(006060)];  
  5.    view02_sub.backgroundColor = [UIColor colorWithRed:1.000 green:0.908 blue:0.552 alpha:1.000];  
  6.    [view02 addSubview:view02_sub];  
  7.    [self printFrameAndBounds:view02 viewOfSub:view02_sub];  
  8.    [UIView animateWithDuration:1 animations:^{  
  9.        // setBounds 強制將自己座標系的左上角點改為(-30,-30)。那麼真正的原點(0,0)自然向右下角偏移(30,30);
  10.        // 注意:setBounds中的(x,y)只改變自己的座標系統。子view的bounds和frame並不會改變。
  11.        [view02 setBounds:CGRectMake(-30, -30200200)];  
  12.    } completion:^(BOOL finished) {  
  13.        [self printFrameAndBounds:view02 viewOfSub:view02_sub];  
  14.    }];  

列印結果如下:


執行效果圖如下:


我們通過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?在CODE上檢視程式碼片派生到我的程式碼片
  1. UIView *view02 = [[UIView alloc] initWithFrame:CGRectMake(100100200200)];  
  2.     view02.backgroundColor = [UIColor colorWithWhite:0.851 alpha: