1. 程式人生 > >導航欄下extendedLayoutIncludesOpaqueBars、automaticallyAdjustsScrollViewInsets等幾個屬性的詳解

導航欄下extendedLayoutIncludesOpaqueBars、automaticallyAdjustsScrollViewInsets等幾個屬性的詳解

  在引入了導航控制器UINavigationController和分欄控制器UITabBarController之後,我們在設定控制元件的frame的時候就需要注意避開導航欄UINavigationBar 44+電源欄UIStatusBar 20的高度,和底部分欄UITabBar 44的高度。底部分欄並沒有太多需要處理的,我們只需要在計算高度的時候避開這44就可以了。而導航欄因為包含透明/半透明、第一個控制元件是否是UIScrollView或其子類等造成frame.origin.y的起點不同。我們現在來分析一下。

  1.edgesForExtendedLayout:UIRectEdge 擴展布局的邊緣

  在iOS7以後 UIViewController 開始使用全屏佈局,而且是預設的屬性。通常涉及到佈局,就離不開這個屬性 edgesForExtendedLayout,它是一個型別為UIExtendedEdge的屬性,指定UIViewController上的根檢視self.view邊緣要延伸的方向。由於iOS7鼓勵全屏佈局,所以它的預設值是UIRectEdgeAll,四周邊緣均延伸,就是說,如果即使檢視中上有UINavigationBar,下有UITabBar,那麼檢視仍會延伸覆蓋到四周的區域。

  (1)UIRectEdgeAll(Defalut)

                                圖1

  這裡放置了一個frame為(00100100)的view,backgroundColor設定為redColor,就是這個樣子。也就是說,此時的self.view是從螢幕頂到螢幕底的。此時我們計算控制元件frame的y的時候,如果想把控制元件在導航欄底部開始,那麼y就是64。

  (2)UIRectEdgeNone

  因此,我們為了不讓我們的控制元件UIView延伸到UINavigationBar下面,我們可以將該屬性設定為UIRectEdgeNone。程式碼如下:

 1   [self setEdgesForExtendedLayout:UIRectEdgeNone]; 

  ps:鑑於之前程式碼OC與Swift都有,可能帶來的閱讀不習慣,以後貼程式碼儘量使用OC,Swift獨有的那就沒辦法了。

                                圖2

  很清晰的可以看出來在設定為UIRectEdgeNone之後,self.view的是從導航欄底部到底部分欄頂部的。此時我們計算控制元件frame的y的時候,如果想把控制元件在導航欄底部開始,那麼y就是0。

  (3)UIRectEdge

複製程式碼
 1 typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
 2 
 3     UIRectEdgeNone   = 0,
 4 
 5     UIRectEdgeTop    = 1 << 0,
 6 
 7     UIRectEdgeLeft   = 1 << 1,
 8 
 9     UIRectEdgeBottom = 1 << 2,
10 
11     UIRectEdgeRight  = 1 << 3,
12 
13     UIRectEdgeAll    = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight  
14 
15 } NS_ENUM_AVAILABLE_IOS(7_0);
複製程式碼

  很明顯,UIRectEdge是個列舉型別。我們已經分析完了UIRectEdgeNone和UIRectEdgeAll,那麼對UIRectEdgeTop和UIRectEdgeBottom也應該有所瞭解了。UIRectEdgeLeft/UIRectEdgeRight也不難猜測,就是對左右的擴充套件。目前沒有遇到過左右兩邊系統控制元件可能覆蓋掉自定義控制元件的情況,但遇到了我想大家也應該心裡有數了吧。

  2.translucent:Bool 半透明的

  這個是self.navigationController.navigationBar的屬性,設定導航條UINavigationBar是否半透明。預設是YES,也就是半透明,看起來比較高大上,與圖1效果相同。

  當設定為不透明NO的時候,就涉及到下面第三條屬性了,不過在第三條預設的情況下,則被下壓,與圖2效果相同。

 1   [self.navigationController.navigationBar setTranslucent:NO]; 


          圖3

  圖中空出的部分,即為導航條UINavigationBar。此時計算frame應從導航欄下部為0開始計算,或者說控制元件會被下壓64。

  不過我們一般不會使用到這一條,因為半透明效果比較好看啊~

  3.extendedLayoutIncludesOpaqueBars:Bool 不透明的條下是否可以擴充套件

  很明顯,這條需要與上一條translucent搭配使用的,預設為NO,也就是不可以擴充套件。當translucent設定為NO,即導航欄UINavigationBar不透明的時候,預設不能擴充套件。若我們設定為YES,則會出現這種情況:

        圖4

  我並沒有改變紅色view的frame,而是被不透明的導航條蓋住看不到了。很明顯此時計算frame又是從螢幕最上方作為0開始計算了。

  為了計算究竟是在電源條下方還是螢幕最上方作為y的0點,改變了紅色view的height為64和65重複試驗,結果如下

      圖5:64開始

       圖6:65開始

  結論是從螢幕上方作為y的0開始計算。

  不過第2條都很少用,第3條使用的機率...

  4.automaticallyAdjustsScrollViewInsets:Bool 自動校準滾動檢視的嵌入檢視

  這個其實就很簡單了,也是我們最常使用的一個吧。automaticallyAdjustsScrollViewInsets是一個bool型別,預設為YES,也就是會自動校準滾動檢視的嵌入檢視。不過這個只針對於UIScrollView及其子檢視,所以我們是用UITextView做一下測試。

  建立了一個frame為(00, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)佔據整個螢幕的UITextView,並放置了足夠多的文字。在預設automaticallyAdjustsScrollViewInsets為YES的前提下,我們測試下可能出現的結果。

 

            圖7 

  似乎什麼毛病都沒有啊很正常啊。但是不要忘記我設定的frame的y是0啊。那大家可能就好奇了,難道UIScrollView的滾動檢視的frame是從導航欄下邊界算起的?

  不忙,我們設定automaticallyAdjustsScrollViewInsets為NO再試試。

 1   [self setAutomaticallyAdjustsScrollViewInsets:NO]; 

        圖8

  這個是一啟動就出現的介面,我並沒有向上滑動它的內容區域,也就是說,似乎此時的frame又是從螢幕下方開始的了。

  不要慌,我們改一下設定試試看。

  我將UITextView的frame設定為(064, [UIScreen mainScreen].bounds.size.width, [UIScreenmainScreen].bounds.size.height),也就是y改成了64;然後改變了它的背景顏色為紅色redColor;最後將[self setAutomaticallyAdjustsScrollViewInsets:NO];這行程式碼注掉,讓它預設為YES。

  看一下效果。

            圖9

  注意:導航欄是半透明的,所以不存在被壓到紅色看不到的問題,也就是說,UITextView的frame的y的64的位置,是導航欄下方;那麼0自然就是在螢幕下方開始計算了。

  很明顯,automaticallyAdjustsScrollViewInsets改變的並不是UIScrollView的frame,而是它的內容區域contentView的可滾動區域,也就是scrollIndicatorInsets。這是我們能滾到的最大範圍。相當於scrollIndicatorInsets這個屬性UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>)的值從UIEdgeInsetsMake(0000)變為了UIEdgeInsetsMake(64000)。這就是automaticallyAdjustsScrollViewInsets這個屬性的作用。

  另外再說一點,這個automaticallyAdjustsScrollViewInsets的屬性,只對加在self.view上的第一個子檢視起作用,所以我們可以在將UIScrollView載入到self.view上之前先載入一個其他控制元件,這樣也能達到同樣的效果。

 1   [self.view addSubView:[[UIView alloc] init]];