ios開發之UIView和UIViewController

UIView 表示屏幕上的一塊矩形區域,負責渲染區域的內容,而且響應該區域內發生的觸摸事件。它在 iOS App 中佔有絕對重要的地位,由於 iOS 中幾乎全部可視化控件都是 UIView 的子類。程序員

UIView 能夠負責如下幾種任務:設計模式

  • 繪製和動畫
  • 佈局和子視圖管理
  • 事件處理

繪製和動畫

視圖繪製

UIView 是按需繪製的,當整個視圖或者視圖的一部分因爲佈局變化,變成可見的,系統會要求視圖進行繪製。對於那些須要使用 UIKit 或者 CoreGraphics 進行自定義繪製的視圖,系統會調用 drawRect: 方法進行繪製。數組

當視圖內容發生變化時,須要調用 setNeedsDisplay 或者 setNeedsDisplayInRect: 方法,告訴系統該從新繪製這個視圖了。調用這個方法以後,系統會在下一個繪製週期更新這個視圖的內容。因爲系統要等到下一個繪製週期才真正進行繪製,能夠一次性對多個視圖調用 setNeedsDisplay,它們會同時被更新。app

視圖的幾何屬性

視圖有 frame,center,bounds 等幾個基本幾何屬性,其中:iview

  • frame 使用的最多,其座標位置都是相對於父視圖的,能夠用於肯定本視圖在父視圖中的位置和其自身的大小
  • center 的座標位置也是相對於父視圖的,一般用於移動,旋轉等動畫操做
  • bounds 是相對於自身的,一般狀況下就是(0,0,width,height), bounds 的含義能夠認爲是當前 view 被容許繪製的範圍

視圖的 ContentMode

視圖在初次繪製完成後,系統會對繪製結果進行快照,以後儘量地使用快照,避免從新繪製。若是視圖的幾何屬性發生改變,系統會根據視圖的 contentMode 來決定如何改變顯示效果。函數

默認的 contentMode 是 UIViewContentModeScaleToFill ,系統會拉伸當前的快照,使其符合新的 frame 尺寸。大部分 contentMode 都會對當前的快照進行拉伸或者移動等操做。若是須要從新繪製,能夠把 contentMode 設置爲 UIViewContentModeRedraw,強制視圖在改變大小之類的操做時調用drawRect:重繪。佈局

動畫

能夠以動畫的形式改變視圖的下面這些屬性,只須要告訴系統動畫開始和結束時的數值,系統會自動處理中間的過渡過程。動畫

frame
bounds
center
transform
alpha
backgroundColor
contentStretch

 

佈局和子視圖管理

除了提供視圖自己的內容以外,一個視圖也能夠表現得像一個容器。當一個視圖包含其餘視圖時,兩個視圖之間就建立了一個父子關係。在這個關係中子視圖被稱爲 subView ,父視圖被稱爲 superView 。一個視圖能夠包含多個子視圖,它們被存放在這個視圖的 subviews 數組裏。添加,刪除,以及操做這些子視圖的相對位置的函數以下:ui

addSubview:
insertSubview:...
bringSubviewToFront:
sendSubviewToBack:
exchangeSubviewAtIndex:withSubviewAtIndex:
removeFromSuperview(子視圖調用)

 

AutoResizing 和 Constraint

當一個視圖的大小改變時,它的子視圖的位置和大小也須要相應地改變。UIView 支持自動佈局,也能夠手動對子視圖進行佈局。spa

當下列這些事件發生時,須要進行佈局操做:

  • 視圖的 bounds 大小改變#
  • 用戶界面旋轉,一般會致使根視圖控制器的大小改變
  • 視圖的 layer 層的 Core Animation sublayers 發生改變
  • 程序調用視圖的setNeedsLayoutlayoutIfNeeded方法
  • 程序調用視圖 layer 的setNeedsLayout方法

Auto Resizing

視圖的autoresizesSubviews屬性決定了在視圖大小發生變化時,如何自動調節子視圖。

可使用的掩碼以下:

UIViewAutoresizingNone
UIViewAutoresizingFlexibleHeight
UIViewAutoresizingFlexibleWidth
UIViewAutoresizingFlexibleLeftMargin
UIViewAutoresizingFlexibleRightMargin
UIViewAutoresizingFlexibleBottomMargin
UIViewAutoresizingFlexibleTopMargin

 

能夠經過位運算符將它們組合起來,例如 UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth

Constraint

Constraint 是另外一種用於自動佈局的方法。本質上,Constraint 就是對 UIView 之間兩個屬性的一個約束:

attribute1 == multiplier × attribute2 + constant

 

其中方程兩邊不必定是等於關係,也能夠是大於等於之類的關係。

Constraint 比 AutoResizing 更加靈活和強大,能夠實現複雜的子視圖佈局。

自定義 layout

UIView 當中提供了一個 layoutSubviews 函數,UIView 的子類能夠重載這個函數,以實現更加複雜和精細的子 View 佈局。

蘋果文檔專門強調了,應該只在上面提到的 Autoresizing 和 Constraint 機制不能實現所須要的效果時,才使用 layoutSubviews。並且,layoutSubviews 方法只能被系統觸發調用,程序員不能手動直接調用該方法。

那麼 layoutSubviews 方法具體調用的時機有哪些呢?具體有下面幾種狀況:

  1. 在父 view 的 autoresize mask 爲 ON 的狀況下,addSubview 會致使被 add 的 view 調用 layoutSubviews, 同時 add 的 target view 以及它全部的子 view 都會被調用。
  2. setFrame 當新的 frame 和 舊的不一樣時(即 view 的大小改變時)會調用 layoutSubviews
  3. 滾動一個 UIScollView 會致使這個 scrollView 以及它的父 View 調用 layoutSubviews
  4. 旋轉設備會致使當前所響應的 ViewController 的主 View 調用 layoutSubviews
  5. 改變 View 的 size 會致使父 View 調用 layoutSubviews
  6. removeFromSuperview 也會致使父 View 調用 layoutSubviews

事件處理

UIView 是 UIResponder 的子類,能夠響應觸控事件。

一般可使用 addGestureRecognizer: 添加手勢識別器來響應觸控事件,若是須要手動處理,則按須要重載 UIView 中的下面四個函數:

touchesBegan:withEvent:
touchesMoved:withEvent:
touchesEnded:withEvent:
touchesCancelled:withEvent:

 

 

UIViewController(視圖控制器),顧名思義,是 MVC 設計模式中的控制器部分。UIViewController 在 UIKit 中主要功能是用於控制畫面的切換,其中的 view 屬性(UIView 類型)管理整個畫面的外觀。

UIViewController 生命週期

ViewController 生命週期的第一步是初始化。不過具體調用的方法還有所不一樣。若是使用 StoryBoard 來建立 ViewController,咱們不須要顯式地去初始化,Storyboard 會自動使用 initWithCoder: 進行初始化。若是不使用 StoryBoard,咱們可使用 init: 函數進行初始化,init: 函數在實現過程當中還會調用 initWithNibName:bundle:。 咱們應該儘可能避免在 VC 外部調用 initWithNibName:bundle:,而是把它放在 VC 的內部(參考這裏)。

初始化完成後,VC 的生命週期會通過下面幾個函數:

(void)loadView
(void)viewDidLoad
(void)viewWillAppear
(void)viewWillLayoutSubviews
(void)viewDidLayoutSubviews
(void)viewDidAppear
(void)viewWillDisappear
(void)viewDidDisappear

 

假設如今有一個 AViewController(簡稱 Avc) 和 BViewController (簡稱 Bvc),經過 navigationController 的 push 實現 Avc 到 Bvc 的跳轉,下面是各個方法的執行執行順序:

1. A viewDidLoad  
2. A viewWillAppear  
3. A viewDidAppear  
4. B viewDidLoad  
5. A viewWillDisappear  
6. B viewWillAppear  
7. A viewDidDisappear  
8. B viewDidAppear 

 

若是再從 Bvc 跳回 Avc,會產生下面的執行順序:

1. B viewWillDisappear  
2. A viewWillAppear  
3. B viewDidDisappear  
4. A viewDidAppear  

 

可見 viewDidLoad 只會調用一次,再第二次跳回 Avc 的時候,AViewController 仍然存在於內存中,也就不須要 load 了。

注意上面的生命週期中都沒有提到有關 ViewController 銷燬的內容,在 iOS 4 & 5 中 ViewController 中有一個 viewDidUnload 方法。當內存不足,應用收到 Memory warning 時,系統會自動調用當前沒在界面上的 ViewController 的 viewDidUnload 方法。 一般狀況下,這些未顯示在界面上的 ViewController 是 UINavigationController Push 棧中未在棧頂的 ViewController,以及 UITabBarViewController 中未顯示的子 ViewController。這些 View Controller 都會在 Memory Warning 事件發生時,被系統自動調用 viewDidUnload 方法。

從 iOS 6 開始,viewDidUnload 方法被廢棄掉了,應用受到 memory warning 時也不會再調用 viewDidUnload 方法。咱們能夠經過重載 - (void)didReceiveMemoryWarning 和 -(void)dealloc 來進行清理工做。

相關文章
相關標籤/搜索