天天看點

《iOS創意程式設計家》——第6.2節導航欄控制器UINavigationController

本節書摘來自異步社群《ios創意程式設計家》一書中的第6章,第6.2節導航欄控制器uinavigationcontroller,作者 林柏全,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

6.2 導航欄控制器uinavigationcontroller

ios創意程式設計家

導航欄控制器(uinavigationcontroller)位于界面的最上方,主要用于将具有因果關系的界面連接配接起來,它由幾個元素組成:左邊按鈕、右邊按鈕以及标題。我們可以通過導航欄的navigationitem來通路這3個元素。其中,左右兩邊的按鈕都是uibarbuttonitem類,我們可以通過navigationitem.rightbarbuttonitem以及navigationitem.leftbarbuttonitem來設定這兩個按鈕。如果希望界面上不出現任何一邊的按鈕,那麼隻要将其設定為nil就可以了。至于中間标題的部分,我們也可以通過titleview來通路。例如:

由于titleview本身就是一個uiview,是以,也可以通過addsubview:的方式将其他界面控件加入到标題欄中。

從故事闆中,我們可以很清楚地看出導航欄應用程式中界面的組成方式。這些界面形成了界面堆棧,由導航欄負責維護這些界面間的前後關系,如圖6.5所示。

《iOS創意程式設計家》——第6.2節導航欄控制器UINavigationController

6.2.1 界面堆棧的概念

界面堆棧主要負責維護界面間的前後關系,不過,這裡所謂的界面是以uiviewcontroller為機關的,而不是uiview。它有點像是界面的曆史記錄,可以讓您回到上一個界面。在uinavigation-controller這個類中,有一個viewcontrollers屬性,您可以很輕易地通過這個屬性來通路界面堆棧,或是通過topviewcontroller來取得位于該堆棧内最上層的界面。

那麼,我們怎麼将界面推入這個堆棧裡面呢?除了通過viewcontrollers這個屬性外,也可以通過pushviewcontroller:animated:來将另一個uiviewcontroller推入到堆棧中。被推入堆棧後的uiviewcontroller所控制的界面就會位于該堆棧内最上層的界面,進而形成了界面切換的效果。pushviewcontroller:在使用的時候有一個限制,其後面的參數隻能是uiviewcontroller,而不能是uinavigationcontroller。如果您執意要将uinavigationcontroller推入堆棧,那麼應該使用presentviewcontroller: animated: completion:來取代上面的方法。

好了,現在來看看在這個堆棧的過程中發生了哪些事情。當一個uiviewcontroller被置入堆棧裡面的時候,它會變為該堆棧裡面最上層的界面控制器,當然,導航欄的界面也會随之更新,界面也會自動調整為适當的大小。這個時候,您可以發現導航欄的左邊出現了一個按鈕,而這個按鈕上的文字正是上一個界面的标題。

這個标題的文字其實是在每一個uiviewcontroller設定好的,您可以通過title屬性來設定每一個界面的标題。如果忘了設定這些界面的标題,您将看不到傳回鍵,但是,在相對應的位置按下時,這些傳回鍵仍會有作用。除了使用上一頁的标題作為傳回鍵的文字外,也可以通過navigationitem.back

barbuttonitem來指定一個自定義的按鈕或标題。不論是通過title還是navigationitem.backbar

buttonitem來設定傳回鍵,您都應該在上一頁的uiviewcontroller中設定,而不是在目前的頁面内設定。

現在試着查詢uiviewcontroller的api,您會發現一件很有趣的事情,原來的uiviewcontroller中就有一個navigationcontroller的屬性(而uinavigationcontoller中有viewcontrollers屬性)。如果在建立項目的時候不是使用master-detail應用程式樣闆的話,那麼這個屬性将會是nil,這是因為master-detail的應用程式已經幫您做好了關聯。關于這一點,大家可以通過編輯器的版本模式來觀察。

現在我們來看看相反的操作,也就是讓界面回到上一頁。可以通過uinavigationcontroller的popviewcontrolleranimated:方法來回到上一個界面,或是通過poptorootviewcontroller- animated:方法來将堆棧中除了最開始的界面外的界面全部退出堆棧。

好了,了解界面堆棧的使用後,我們來看一個實際的例子。您可以先把其他的界面準備好,然後通過uiviewcontroller類的initwithnibname加載進來。例如,可以在xcode産生的viewcontroller類裡面用下面這樣的方式來切換界面。

6.2.2 使用故事闆來處理界面堆棧

如果完全采用故事闆的方式來設計界面,那麼不需要使用諸如pushviewcontroller:animated:的方式來處理界面堆棧。可以直接在兩個界面間設定好它們的連接配接(segue),然後一切的工作就交由系統自己去處理了。不過有些時候,兩個界面間的連接配接也有可能會有多種情況發生,這通常是因為使用者在第1個界面做了某些操作而導緻第2個界面出現的結果不同。這時候,我們可以設定多個連接配接(segue),然後再由程式去判斷要走哪一條路徑。

比如,在下面的界面中,我們可以将輸入密碼的界面與登入成功和登入失敗的界面分别連接配接起來。選中連接配接後,在屬性觀測視窗中為每個連接配接設定一個辨別符,在程式裡面就可以通過這個辨別符來判斷要走的路徑,如圖6.6所示。例如,可以在第一個界面的view controller中寫入如下程式代碼。

這樣一來,界面就會跟着程式内的邏輯來跑了。

《iOS創意程式設計家》——第6.2節導航欄控制器UINavigationController

注意:

① 如果嘗試将按鈕連結到下一個界面,會發現路徑隻能有一個。如果希望做到上述的效果,那麼應該将兩個view controller連接配接起來才對。

② 除了上述的方式外,也可以在appdelegate.m中去編寫這樣的程式代碼,以決定第一個界面是什麼。其中,“loginviewcontroller”與“viewcontroller”是我們為不同的view controller在屬性觀測視窗(attribute inspector)所設定的辨別符。

6.2.3 單選按鈕

iphone内建的通訊錄其實就是一個很典型的導航欄模式,讀者們應該也注意到了吧。我們可以看到在導航欄的右邊有一個加号的按鈕,這是怎麼加上去的呢?其實導航欄控制器已經預留了左右兩邊的按鈕。您可以在導航欄的兩邊各放入一個uibarbuttonitem類的按鈕,使用的代碼如下:

把rightbarbuttonitem 或leftbarbuttonitem設定為nil時,導航欄原有的按鈕就不見了,這個技巧可以應用到諸如文本編輯器這樣的應用程式上。我們在第5章的uitextviewdemo的例子裡面就已經運用了這個技巧。

可以使用的按鈕的類型包括以下幾種:

如果不想使用自定義的按鈕樣式,也可以直接使用系統内定的按鈕類型,不過在初始化的時候得改用initwithbarbuttonsystemitem:的構造函數,使用代碼如下:

值得一提的是,一旦決定使用系統按鈕,您将無法改變上面的标題文字;反之,可以通過uibarbuttonitem的title屬性來動态地改變上面的文字。除了文字的按鈕外,也可以通過圖檔的方式來呈現,使用代碼如下:

6.2.4 如何建立導航欄應用程式

在所有的項目樣闆中隻有master-detail的應用程式才會預設産生導航欄,在其他的樣闆中,我們都得自己去建立一個導航欄控制器。下面的内容将介紹如何在設計界面中建立導航欄控制器。可以使用xib或是故事闆來建立這個應用程式,如果可能的話,盡量使用故事闆的方式,在開發上會更為直覺些。

請記得勾選“use storyboard”以及“use automatic reference counting”選項。

如同往常一樣,您應該可以看到一個空白的手機界面。現在,選中這個view controller,并按下删除鍵将這個界面删除。現在的界面上應該是空無一物了。

導航欄控制器預設會帶有一個uiviewcontroller,而這個uiviewcontroller就是它的界面堆棧内的第一個界面。現在,可以試着在這個uiviewcontroller的标題欄的地方輕按兩下後輸入它的标題文字。現在的界面看起來應該如圖6.7所示。

《iOS創意程式設計家》——第6.2節導航欄控制器UINavigationController

完成之後,可以試着執行應用程式,您會發現界面上竟然是一片黑色的界面,這是因為我們還沒有指定故事從哪邊開始的緣故。

每個故事闆的一開始一定要有一個起始的界面控制器。是以請選中界面中的navigation controller控制器,切換到屬性觀測視窗,并勾選“is initial view controller”,如圖6.8所示。現在再試着執行看看,您應該可以看到第一個界面了。

《iOS創意程式設計家》——第6.2節導航欄控制器UINavigationController

接下來,我們要産生第2個界面。還記得導航欄控制器是将整個uiviewcontroller推入到界面的堆棧裡面吧。是以,在這裡,我們必須要由控件庫中拉入一個非導航欄的控制器。例如一個uiviewcontroller,如圖6.10所示。

《iOS創意程式設計家》——第6.2節導航欄控制器UINavigationController

現在再執行一下您的應用程式,應該可以順利地由第1個界面切換到第2個界面了。

繼續閱讀