iOS Programming - 第五章 視圖控制器

iOS Programming - 第五章 視圖控制器


視圖控制器是 UIViewController 的子類的一個(gè)實(shí)例。 視圖控制器管理著視圖層級(jí)。它負(fù)責(zé)創(chuàng)建組成視圖層級(jí)的視圖對(duì)象并在視圖層級(jí)中處理跟視圖對(duì)象關(guān)聯(lián)的事件。

視圖控制器中的 View


作為 UIViewController 的子類, 所有的視圖控制器都繼承了一個(gè)重要的屬性:

var view: UIView!

這個(gè)屬性指向一個(gè) UIView 實(shí)例, 這個(gè) view 是視圖控制器的視圖層級(jí)中的根視圖。當(dāng)視圖控制器的 view 被作為 window 的子視圖添加時(shí), 該視圖控制器的整個(gè)視圖層級(jí)就被添加上了。

img
img

視圖控制器的 view 直到它需要出現(xiàn)在屏幕上時(shí)才被創(chuàng)建。這種優(yōu)化叫做懶加載(lazy loading), 這能減少內(nèi)存使用并提升性能。

視圖控制器有兩種方式創(chuàng)建它的視圖層級(jí):

  • 編寫(xiě)程序, 通過(guò)重寫(xiě) UIViewControllerloadView 方法
  • Interface Builder 中, 通過(guò)使用諸如 storyboard 的界面文件

在第三章中你已經(jīng)使用了這兩種方法, 在第六章中你將使用 loadView() 創(chuàng)建程序上的視圖。

設(shè)置初始的視圖控制器


每個(gè) storyboard 都可以有很多視圖控制器, 但是每個(gè) storyboard 文件只有一個(gè)初始視圖控制器(initial view controller)。 初始視圖控制器是 storyboard 的入口點(diǎn)。你將在畫(huà)布中添加并配置另外一個(gè)視圖控制器并把該控制器設(shè)置為 storyboard 的初始視圖控制器。

打開(kāi) Main.storyboard, 從對(duì)象庫(kù)中, 拖拽一個(gè) ViewController 到畫(huà)布中, 如果你用完了可用的空間, 你可以按住 Ctrl 并單擊背景視圖來(lái)選擇不同的縮放比例。

img

用這個(gè)視圖控制器來(lái)顯示 MKMapView。先選中這個(gè) View Controllerview, 而不是 View Controller 自身! — 并按下 Delete 鍵來(lái)從畫(huà)布中刪除這個(gè) view。 然后從對(duì)象庫(kù)中拖拽一個(gè) Map Kit View 到這個(gè)視圖控制器中以把它設(shè)置為該視圖控制器的 view。

img

選中 View Controller 并打開(kāi)它的屬性檢查器。勾選 Initial View Controller , 則該視圖控制器的前面會(huì)出現(xiàn)一個(gè)灰色的箭頭。

MKMapView 是一個(gè)當(dāng)前未被加載到程序中的框架??蚣苁且粋€(gè)共享代碼庫(kù), 里面包含諸如界面文件和圖片等關(guān)聯(lián)的資源。

現(xiàn)在你需要導(dǎo)入 MapKit 框架以加載 MKMapView。使用 import 關(guān)鍵字但不使用包含任何使用該框架的代碼來(lái)導(dǎo)入 MapKit 會(huì)導(dǎo)致編譯器把它優(yōu)化掉 — 即使你在 storyboard 中使用 map view。

相反, 你需要手動(dòng)地把 MapKit 鏈接到 app 中。

打開(kāi)工程導(dǎo)航, 點(diǎn)擊工程名。在設(shè)置中打開(kāi) General 標(biāo)簽, 滾動(dòng)到最底部找到 Linked Frameworks and Libraries。 點(diǎn)擊 + 號(hào)并搜索 MapKit.framework, 選中這個(gè)框架并點(diǎn)擊 Add。

img

UITabBarController


UITabBarController 保存了一個(gè)視圖控制器的數(shù)組。UITabBarController 也在屏幕底部維護(hù)了一個(gè) tab bar, 數(shù)組中每個(gè)視圖控制器都帶有一個(gè) tab bar。觸摸標(biāo)簽(tab)會(huì)呈現(xiàn)跟該標(biāo)簽(tab)相關(guān)聯(lián)的視圖控制器。

打開(kāi) Main.stroyboard 并選擇 View Controller。 從 Editor 菜單中, 選擇 Embed In -> Tab Bar Controller。 這會(huì)把 View Controller 添加到 Tab Bar Controller 的視圖控制器數(shù)組中去。

按住 Control 鍵從 Tab Bar Controller 拖拽到 Conversion View Controller 上。在彈出的 Relationship Segue 一欄, 選擇 view controllers。

img

構(gòu)建并運(yùn)行該程序。此時(shí)標(biāo)簽上僅僅顯示的文字是默認(rèn)的 "Item"。在下一節(jié), 你可以更新 tab bar items 以使 tabs 更具描述性。

UITabBarController 自身是一個(gè) UIViewController 的子類。 UITabBarControllerview 是一個(gè)含有兩個(gè)子視圖的 UIView: 即 tab bar 和 所選擇的視圖控制器的 view。

img

Tab bar items


tab bar 上的每個(gè)標(biāo)簽(tab)能展示一個(gè)標(biāo)題(title)和圖片(image), 為了這個(gè)目的, 每個(gè)視圖控制器維護(hù)了一個(gè) tabBarItem 屬性。當(dāng)視圖控制器被包含在 UITabBarController 中時(shí), 該視圖控制器的 tab bar item 會(huì)出現(xiàn)在 tab bar 中。

img

Assets.xcassets 中拖入素材。

tab bar item 屬性既能通過(guò) storyboard 也能通過(guò)編程來(lái)設(shè)置。

在 storyboard 中, 定位到 View Controller。 注意, 當(dāng)視圖控制器將被呈現(xiàn)在 tab bar controller 時(shí), 帶有 tab bar itemtab bar 被添加到界面中。這在布局你的界面時(shí)會(huì)很有用。

選擇這個(gè) tab bar item 并打開(kāi)它的屬性檢查器。 在 Bar Item 欄, 把 Title 設(shè)置為 "Map" 并從 Image 菜單中選擇 MapIcon。你也可以在畫(huà)布中雙擊文本來(lái)更改 tab bar item 的文本。

img

你還可以拖拽 tab bar item 以改變它們呈現(xiàn)的位置。

Loaded and Appearing Views


當(dāng)程序啟動(dòng)時(shí), tab bar controller 默認(rèn)會(huì)加載它的數(shù)組中的第一個(gè)視圖控制器的 view, 即 ConversionViewController。 這意味著 MapViewController 的 view 直到用戶點(diǎn)擊它的時(shí)候才被加載。

你可以自己測(cè)試這種懶加載行為。當(dāng)視圖控制器加載完它的視圖后, 會(huì)調(diào)用 viewDidLoad() 方法, 你可以重寫(xiě)該方法以打印信息到控制臺(tái)中。

你將為這兩個(gè)視圖控制器寫(xiě)代碼。 然而, 展示 map 的視圖控制器當(dāng)前并沒(méi)有代碼與之關(guān)聯(lián), 因?yàn)樗械呐渲枚际鞘褂?storyboard。你需要?jiǎng)?chuàng)建一個(gè)視圖控制器的子類并把它關(guān)聯(lián)到界面中。

創(chuàng)建一個(gè)名為 MapViewController 的 UIViewController 子類:

import UIKit

class MapViewController: UIViewController {
    
}

打開(kāi) storyboard 并選中該 map 的視圖控制器。打開(kāi)它的身份檢查器并把它的 Class 更改為 MapViewController

現(xiàn)在你把 MapViewController 類和畫(huà)布中的視圖控制器關(guān)聯(lián)了起來(lái), 你可以在 ConversionViewControllerMapViewController 中添加代碼了。

在 ConversionViewController.swift 中重寫(xiě) viewDidLoad() 方法,

override func viewDidLoad() {
    // Always call the super implementation of viewDidLoad
    super.viewDidLoad()
    print("ConversionViewController loaded its view.")
}

在 MapViewController.swift 中重寫(xiě)同一個(gè)方法:

override func viewDidLoad() {
    // Always call the super implementation of viewDidLoad
    super.viewDidLoad()
    print("MapViewController loaded its view.")
}

程序啟動(dòng)時(shí)就打印 ConversionViewController loaded its view, 當(dāng)點(diǎn)擊 Map Tab 時(shí)才打印 MapViewController loaded its view。并且都只會(huì)打印一次。 如果想執(zhí)行多次某個(gè)事件, 應(yīng)重寫(xiě) viewWillAppearviewWillDisappear。

訪問(wèn)子視圖


通常, 在界面出現(xiàn)在用戶面前之前, 你需要在 Interface Builder 中定義的子視圖中做某些額外的初始化或配置。 所以你從哪里訪問(wèn)子視圖? 有兩種主要的觀點(diǎn), 取決于你需要干什么。一個(gè)地方是在 viewDidLoad() 方法中, 該方法在視圖控制器的界面文件被加載之后調(diào)用, 這時(shí)視圖控制器的所有 outlets 將會(huì)引用合適的對(duì)象。另外一個(gè)地方是在 viewWillAppear(_:) 中。這個(gè)方法在視圖控制器的 view 被添加到 window 上之前被調(diào)用。

你應(yīng)該選擇哪個(gè)方法? 在程序運(yùn)行期間, 如果配置只需要執(zhí)行一次, 就重寫(xiě) viewDidLoad() 。 如果需要在每次視圖控制器的 view 出現(xiàn)在屏幕之前執(zhí)行配置, 那么重寫(xiě) viewWillAppear(_:) 方法。

跟視圖控制器和它們的視圖交互


讓我們看看在視圖控制器和它的視圖的生命周期中所調(diào)用的方法。

  • init(coder: ) 是從 storyboard 創(chuàng)建的 UIViewController 實(shí)例的初始化函數(shù)。

當(dāng)從 storyboard 創(chuàng)建視圖控制器實(shí)例時(shí), 會(huì)調(diào)用一次它的 init(coder:) 方法。在第 15 章中你會(huì)學(xué)到更多關(guān)于該方法的東西。

  • init(nibName:bundle: )UIViewController 的指定初始化構(gòu)造函數(shù)。

當(dāng)不使用 storyboard 創(chuàng)建視圖控制器實(shí)例時(shí), 會(huì)調(diào)用一次它的 init(nibName:bundle: ) 方法。注意在某些 app 中, 你可以創(chuàng)建幾個(gè)同樣的視圖控制器類的實(shí)例。每創(chuàng)建一個(gè)視圖控制器就調(diào)用一次該方法。

  • 重寫(xiě) loadView() 以編程方式創(chuàng)建視圖控制器的 view。
  • 重寫(xiě) viewDidLoad 以配置通過(guò)加載界面文件創(chuàng)建的視圖。該方法在視圖控制器的 view 被創(chuàng)建之后調(diào)用。
  • 重寫(xiě) viewWillAppear(_:) 以配置通過(guò)加載界面文件創(chuàng)建的視圖

該方法和 viewDidAppear(_:) 會(huì)在每次視圖控制器在移動(dòng)到屏幕上時(shí)被調(diào)用。viewWillDisappear(_:)viewDidDisappear(_:) 會(huì)在每次視圖控制器移出屏幕時(shí)調(diào)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容