在ios開發中視圖的切換是很頻繁的,獨立的視圖應用在實際開發過程中并不常見,除非你的應用足夠簡單。在ios開發中常用的視圖切換有三種,今天我們将一一介紹:
<a href="http://www.cnblogs.com/kenshincui/p/3940746.html#uitabbarcontroller">uitabbarcontroller</a>
<a href="http://www.cnblogs.com/kenshincui/p/3940746.html#uinavigationcontroller">uinavigationcontroller</a>
<a href="http://www.cnblogs.com/kenshincui/p/3940746.html#modalwindow">模态視窗</a>
ios三種視圖切換的原理各不相同:
uitabbarcontroller:以平行的方式管理視圖,各個視圖之間往往關系并不大,每個加入到uitabbarcontroller的視圖都會進行初始化即使目前不顯示在界面上,相對比較占用記憶體。
uinavigationcontroller:以棧的方式管理視圖,各個視圖的切換就是壓棧和出棧操作,出棧後的視圖會立即銷毀。
uimodalcontroller:以模态視窗的形式管理視圖,目前視圖關閉前其他視圖上的内容無法操作。
uitabbarcontroller是apple專門為了利用頁簽切換視圖而設計的,在這個視圖控制器中有一個uitabbar控件,使用者通過點選tabbar進行視圖切換。我們知道在uiviewcontroller内部有一個視圖,一旦建立了uiviewcontroller之後預設就會顯示這個視圖,但是uitabbarcontroller本身并不會顯示任何視圖,如果要顯示視圖則必須設定其viewcontrollers屬性(它預設顯示viewcontrollers[0])。這個屬性是一個數組,它維護了所有uitabbarcontroller的子視圖。為了盡可能減少視圖之間的耦合,所有的uitabbarcontroller的子視圖的相關标題、圖示等資訊均由子視圖自己控制,uitabbarcontroller僅僅作為一個容器存在。

假設現在有一個kctabbarviewcontroller(繼承于uitabbarcontroller),它内部有一個kcwebchatviewcontroller、一個kccontactviewcontroller。
1.首先建立一個kctabbarviewcontroller繼承于uitabbarcontroller(代碼是預設生成的,不再貼出來)。
2.其次建立兩個子視圖,在這兩個子視圖控制器中設定對應的名稱、圖示等資訊。
kcwebchatviewcontroller.m
kccontactviewcontroller.m
3.在應用程式啟動後設定tab bar視圖控制器的子視圖,同時将tab bar視圖控制器作為window的根控制器。
appdelegate.m
運作效果:
對于uitabbarcontroller簡單總結如下:
uitabbarcontroller會一次性初始化所有子控制器,但是預設隻加載第一個控制器視圖,其他視圖控制器隻初始化預設不會加載,為了能夠将其他子控制器也正常顯示在tab bar中我們通路了每個子視圖控制器的視圖以便調用其視圖加載方法(viewdidload);當然,既然會調用子視圖的初始化方法,當然也可以将視圖控制器的tabbaritem屬性設定放到init方法中設定,如此則不用再周遊其視圖屬性了。
每個視圖控制器都有一個tabbarcontroller屬性,通過它可以通路所在的uitabbarcontroller,而且對于uitabbarcontroller的直接子視圖其tabbarcontroller等于parentviewcontroller。
每個視圖控制器都有一個tabbaritem屬性,通過它控制視圖在uitabbarcontroller的tabbar中的顯示資訊。
tabbaritem的image屬性必須是png格式(建議大小32*32)并且打開alpha通道否則無法正常顯示。
注意:使用storyboard建立uitabbarcontroller的内容今天不再着重講解,内容比較簡單,大家可以自己試驗。
uinavigationcontroller是一個導航控制器,它用來組織有層次關系的視圖,在uinavigationcontroller中子控制器以棧的形式存儲,隻有在棧頂的控制器能夠顯示在界面中,一旦一個子控制器出棧則會被銷毀。uinavigationcontroller預設也不會顯示任何視圖(這個控制器自身的uiview不會顯示),它必須有一個根控制器rootviewcontroller,而且這個根控制器不會像其他子控制器一樣被銷毀。
下面簡單通過幾個視圖模拟一下微信添加好友的功能,假設有一個導航控制器,它的根控制器為好友清單控制器kcfriendviewcontroller,通過它可以導航到添加qq聯系人視圖kcqqcontactviewcontroller,在qq聯系人視圖又可以導航到公共賬号視圖kcpublicaccountviewcontroller。
1.首先在應用代理啟動後初始化一個導航控制器并設定其根控制器為kcfriendviewcontroller
2.在好友清單視圖控制器中設定導航欄左右按鈕,并且設定點選右側按鈕導航到添加qq聯系人視圖
3.在qq聯系人視圖右側導航中添加一個導航到公共賬号的按鈕
4.在公共賬号視圖中在導航欄右側設定一個按鈕用于直接傳回根視圖
uinavigationcontroller預設顯示一個根控制器,這個根視圖必須指定(前面我們說過uinavigationcontroller和uitabbarcontroller類似僅僅作為導航容器,本身并不會顯示視圖),通過根控制器導航到其他下一級子視圖。
在子視圖中可以通過navigationcontroller通路導航控制器,同時可以通過navigationcontroller的childviewcontrollers獲得目前棧中所有的子視圖(注意每一個出棧的子視圖都會被銷毀)。
uinavigationcontroller導航是通過上方導航欄進行的(類似的uitabbarcontroller是通過下方uitabbar進行導航),每個放到uinavigationcontroller棧中的子視圖都會顯示一個導航欄,可以通過子控制器(包括根控制器)的navigationitem通路這個導航欄,修改其左右兩邊的按鈕内容。
預設情況下除了根控制器之外的其他子控制器左側都會在導航欄左側顯示傳回按鈕,點選可以傳回上一級視圖,同時按鈕标題預設為上一級視圖的标題,可以通過backbarbuttonitem修改。下一級子視圖左側傳回按鈕上的标題的顯示優先級為: 導航欄傳回按鈕backbarbuttonitem的标題(注意不能直接給backbarbuttonitem的标題指派,隻能重新給backbarbuttonitem指派)、導航欄navigationitem的标題,視圖控制器标題。
示範效果:
鑒于很多初學者在學習uinavigationcontroller時看到的多數是使用storyboard方式建立導航,而且storyboard中的segue很多初學者不是很了解,這裡簡單對storyboard方式建立導航進行介紹。
下面簡單做一個類似于ios系統設定的導航程式,系統預設進入settings視圖控制器,在settings界面點選general進行general視圖,點選sounds進入sounds視圖,就那麼簡單。
1.首先在main.storyboard中拖拽一個uinavigationcontroller将應用啟動箭頭拖拽到建立的uinavigationcontroller中将其作為預設啟動視圖,在拖拽過程中會發現uinavigationcontroller預設會帶一個uitableviewcontroller作為其根控制器。
2.設定uitableviewcontroller的标題為“settings”,同時設定uitableview為靜态表格并且包含兩行,分别在兩個uitableviewcell中放置一個uilabel命名為”general”和“sounds”。
3.建立兩個uitableviewcontroller,标題分别設定為“general”、“sounds”,按住ctrl拖拽“settings”的第一個uitableviewcell到視圖控制器“general”,同時選擇segue為“push”,拖拽第二個uitableviewcell到視圖控制器“sounds”,同時選擇segue為“push”。
到這裡其實我們已經可以通過settings視圖導航到general和sounds視圖了,但是storyboard是如何處理導航的呢?
前面我們看到導航的過程是通過一個名為“segue”連接配接建立的(前面采用的是push方式),那麼這個segue是如何工作的呢?segue的工作方式分為以下幾個步驟:
1.建立目标視圖控制器(也就是前面的general、sounds視圖控制器)
2.建立segue對象
3.調用源視圖對象的prepareforsegue:sender:方法
4.調用segue對象的perform方法将目标視圖控制器推送到螢幕
5.釋放segue對象
要解釋上面的過程首先我們定義一個kcsettingstableviewcontroller控制器,它繼承于uitableviewcontroller,然後在storyboard中設定“settings”視圖控制器的class屬性為kcsettingstableviewcontroller。同時設定導航到“general”視圖控制器的segue的identifier為“generalsegue”,設定導航到“sounds”控制器的segue的identifier為“soundssegue”。
然後修改kcsettingstableviewcontroller.m添加如下代碼:
此時運作程式導航我們會發現此方法會被調用的同時可以列印源視圖控制器和目标視圖控制器的資訊,這一步對應上面所說的第三個步驟。
接着在”settings”視圖控制器的導航欄左右兩側分别放一個uibarbuttonitem并添加對應事件代碼如下:
此時運作程式發現,使用兩個按鈕同樣可以導航到對應的視圖控制器,這一步對應上面第四個步驟,隻是預設情況下是自己執行的,這裡我們通過手動調用來示範了這個過程。
運作效果如下:
模态視窗隻是視圖控制器顯示的一種方式(在ios中并沒有專門的模态視窗類),模态視窗不依賴于控制器容器(例如前兩種視圖切換一個依賴于uitabbarcontroller,另一個依賴于uinavigationcontroller),通常用于顯示獨立的内容,在模态視窗顯示的時其他視圖的内容無法進行操作。
模态視窗使用起來比較容易,一般的視圖控制器隻要調用- (void)presentviewcontroller:(uiviewcontroller *)viewcontrollertopresent animated: (bool)flag completion:(void (^)(void))completion ns_available_ios(5_0);方法那麼參數中的視圖控制器就會以模态視窗的形式展現,同時調用- (void)dismissviewcontrolleranimated: (bool)flag completion: (void (^)(void))completion ns_available_ios(5_0);方法就會關閉模态視窗。
下面的示例中示範了一個登入操作,點選主界面左上方登入按鈕以模态視窗的形式展現登入界面,使用者點選登入界面中的登入按鈕就會傳回到主界面。特别強調一點在下面的示例中導航欄是手動建立的,而不是采用uinavigationcontroller,為了幫助大家熟悉導航欄使用同時也了解了uinavigationcontroller中導航欄的本質。
1.首先建立一個登入界面,在界面中隻有兩個輸入框和一個登入按鈕
2.定義主界面視圖控制器kcmainviewcontroller,在左上角放一個登入按鈕用于彈出登入界面
假設使用者名輸入“kenshincui”,密碼輸入“123”就認為登入成功,否則登入失敗。同時登入成功之後在主視圖控制器中顯示使用者名并且登入按鈕變成“登出”。要實作這個功能主要的問題就是如何把登入後的使用者名資訊傳遞到主界面?由此引出一個問題:多視圖參數傳遞。
在ios開發中常用的參數傳遞有以下幾種方法:
采用代理模式
采用ios消息機制
通過nsdefault存儲(或者檔案、資料庫存儲等)
通過appdelegate定義全局變量(或者使用uiapplication、定義一個單例類等)
通過控制器屬性傳遞
今天我們主要采用第一種方式進行資料傳遞,這在ios開發中也是最常見的一種多視圖傳參方式。使用代理方式傳遞參數的步驟如下:
1.定義協定,協定中定義好傳參時所需要的方法
2.目标視圖控制器定義一個代理對象
3.源視圖控制器實作協定并在初始化目标控制器時指定目标控制器的代理為其自身
4.需要傳參的時候在目标視窗調用代理的協定方法
具體代碼如下:
kcmainviewcontroller.h
kcmainviewcontroller.m
kcloginviewcontroller.h
kcloginviewcontroller.m
在上面的代碼中,點選登入可以跳轉到登入界面,如果使用者名、密碼輸入正确可以回傳參數到主界面中(不正确則給出提示),同時修改主界面按鈕顯示内容。如果已經登入則點選登出會彈出提示,點選确定登出則會登出登入資訊。在代碼中我們還用到了uiactionsheet和uialert,這兩個控件其實也是模态視窗,隻是沒有鋪滿全屏,大家以後的開發中會經常用到。
假設登入之後在主視圖控制器右上角點選“我”可以彈出目前使用者資訊如何實作呢?這個時候我們需要從主視圖控制器傳遞參數到子視圖控制器,和前面的傳參剛好相反,這個時候我們通常使用上面提到的第五個方法,設定目标視圖控制器的屬性。
1.首先修改一下主視圖控制器
2.添加展示使用者資訊的控制器視圖
kcmeviewcontroller.h
kcmeviewcontroller.m
前面代碼中除了示範了模态視窗的使用還示範了兩種多視圖參數傳遞方法,其他方法日後我們再做介紹。最後完整展現一下整個示例程式:
<a href="http://pan.baidu.com/s/1sjexh5v" target="_blank"></a>