IOS開發入門(11)-導航控制器I:層級結構和標籤
前言:(直接從書上抄的)
大多數應用程序是由主視圖導出多個屏幕,並且通常情況下實現屏幕切換的方法還不止一種。我們需要一種方式來實現用戶在應用程序內來回移動,以及讓用戶知道他們所在的具體部分提供的功能之間的切換。
在iPhone設備上,大多數使用導航控制器的應用程序可以分爲兩種。一種使用簡單的主視圖來導航一系列展示或多或少、漸進的細節場景。通訊錄、筆記和設置就是不錯的示例。其他的,比如鬧鐘和音樂,則有許多主視圖,各自擁有不同的功能,設置擁有自己的內容層次。
iOS提供控制器來管理每種內容之間的導航。UINavigationController用於在各種層次結構的信息之間上下移動,而UITabBarController則處理多個主視圖之間的切換。
本節就是介紹這兩種方法怎麼使用。
1 導航控制器
我們來看一下設置是長啥樣的吧,下圖展示的是setting方法應用程序中的某個局部的層級結構
在iPhone上,這是常見的組織內容的方式。該方式優雅地解決了如何在狹小空間內顯示大量內容的問題。setting允許修改iPhone和setting內部各種應用程序的數以百計的設置選項。採用層次結構的方式來“摺疊”內容,能夠很好地應用兩種屏幕尺寸,以及很好地複合人們通常善於分類和分組的情況。
那些擁有帶層次結構的內容的應用程序,工作方式一般基本相同。在屏幕層級的頂部,會有內容概述,然後就是多個帶更多細節的屏幕。setting應用程序就是不錯的示例。在頂層,一開始是setting應用的所有相關的分類,然後是能夠持續向下深入,直到到達特定設置的細節。
UINavigationController正是爲了處理這種類型的導航而設。他跟蹤客戶,就像它位於導航中不同屏幕的層次結構,並提供默認的控件返回。該控制器通過將所有內容都嵌入它內部來實現這一點。
上圖顯示了導航控制器的一部分。頂部是導航欄。導航欄通常會用在上下文中或展開的當前路徑。標題通常爲用戶正在觀看的內容。正如我們很快就會看到的一樣,在導航路徑中,左手邊的後退按鈕能夠讓用戶返回上一節。在導航欄上,用戶可以自定義按鈕
位於底部的是一個可選的工具欄,是另一處讓我們設置空間的地方,上面放了一個操作按鈕。我們的視圖控制器位於灰色地帶。而在當前場景的某個地方,需要提供一個方法來打開下一級詳細頁面。例如,在Add/View場景中的Edit按鈕
當使用導航控制器時,一開始可以將它連接到第一個場景或根場景(一個視圖控制器)。當導航控制器打開時,他就會打開根場景。正如我們將其關聯到一個新的場景(視圖控制器),導航控制器會將它放在當前路徑上,並顯示該場景。
在視圖控制器的堆棧中,根視圖位於底部,路徑通常也會被記錄。
介紹一下導航控制類
所有的導航功能都通過5個主要類來提供:
- UINavigationController爲當前導航堆棧協調所有的組件。除了管理導航堆棧和所有磚廠(transition)之外,它有指向導航欄和可選工具欄的引用
- UINavigationBar是位於屏幕頂部的導航欄視圖。UINavigationController用它顯示當前場景的標題和一個按鈕,如果需要的話,它可以用於返回前一個界面。它可以獨立地使用,但是不推薦這樣做
- UINavigationItem管理層次結構中某個特定視圖控制器的UINavigationBar。它有如下各項的屬性:設置標題,顯示、添加和隱藏工具欄按鈕,包括Back按鈕
- UIBarButtonItem提供了一個對象來管理導航和工具欄上的按鈕。從系統提供按鈕(如Done(完成)、Cancel(取消)和到文本按鈕的操作(action)等),可以創建出任意按鈕。Button Item既不是UIButton,也不是視圖(View)類型。它們是管理項,可以顯示用戶界面中的東西。可以將UIButton放在Button Item(按鈕項)裏面
UIToolbar管理一個可選的工具欄,通常位於屏幕的底部。其擁有方法與屬性來設置Button Item(按鈕項)和外觀,以及一種方式來指定其位置是在屏幕的頂部還是底部
UINavigationItem使用當前視圖控制器的title屬性來設置文本。更改title會改變文本。之前在本地化的場景標題我們見過這個操作。
下圖顯示了在CarValet應用程序的Add/View場景中與導航控制器相關的對象
導航控制器管理Add/View場景以及其他場景。每個被管理的場景有一個UINavigationItem,用於設置導航欄的內容以及標題。Add/View場景的標題欄也有一個工具欄按鈕,以顯示car images場景。
觀看上圖的圈圈,這是一個特殊的關聯標識符(segue identifier),是爲第一個控制器或根視圖控制器而設。不想push segue,着開起來想一條兩端都有一個圓的線。根場景是導航控制器展示的第一個場景。故事版中的另一個鏈接顯示了場景之間的導航路徑。例如在Add/View於Edit場景之間存在一個鏈接。因爲無處可去只有返回,Edit場景就是一個葉節點,如同第一張圖的葉節點。
添加工具欄
(從書上抄了那麼多字真是類,覺得還是介紹一下比較好),現在開始幹正事。
首先我們要把圖標添加到項目的資產庫中。我們需要圖標,可以
在這裏下載,但是那需要自己找;也可以在這裏我的github下載。最好是從我的github上下載吧。
好了,圖標下載完了,要添加到資產庫中,如下圖操作方式
選+之後,會跳出一個目錄,到最下面找到Import,點完import,選中要導入的文件就行啦
- 現在圖標加進去了,我們要加底部工具欄了,打開故事面板
- 添加完工具欄,放置按鈕
選擇左邊的按鈕,Image設置爲sign_out;右邊那個按鈕,Image設置爲sign_in;中間的按鈕,title改爲Edit。
刪除原來的Previous、Next和Edit按鈕,
將我們之前添加的左右箭頭通過下圖方法設置關聯,左箭頭選擇previousCar,右箭頭選擇nextCar
當我們刪除Edit按鈕時,也刪除了到Edit場景的關聯(segue),我們要將它恢復,將它拉到Edit場景,選擇push,並設置標識符爲Editsegue,與之前的Edit按鈕所用的關聯名稱一樣
然後運行程序你可能會發現下面的導航欄沒有出現,那麼在ViewController.m中的viewDidLoad方法中,添加
self.navigationController.toolbarHidden = NO;
使他正好位於[super viewDidLoad];
下面,這時候就出現了,但是點開其他的例如car images,下面也出現了導航欄,這顯然不是我們想要的,在Edit等場景裏面也是這個情況。可以在他們各自的viewDidLoad方法中添加self.navigationController.toolbarHidden = YES;
,這樣就默認爲隱藏了。然而還有個問題,當我們從其他場景退出返回到Add/View場景時,導航欄消失了,他也是被隱藏了,那我們就換個地方,在ViewController.m中的viewWillAppear方法中,添加self.navigationController.toolbarHidden = NO;
,這樣每次加載的時候,就自動設置回去了。這樣就設置完成啦。
(PS,顏色是我後來弄的,到這步按鈕顏色應該是藍色的,導航欄應該是白色的,而且沒有About)
基於消息的導航
到目前爲止,我們已經使用segue在場景之間進行導航,包括使用特使的exit segue。我們擁有一些控制器可以傳遞數據並能使用prepareForSegue:方法修改行爲。藉助於UINavigationController的屬性和消息,可以擁有完全控制權。可以實現如下類似行爲:將新的視圖控制器推給堆棧(push),彈出(pop)當前視圖控制器,彈出根視圖控制器之上的所有控制器,獲取當前導航堆棧中的控制器數組,甚至重新排列視圖控制器數組。
可以使用基於代碼的消息,爲CarValet應用程序添加一個About場景,而不是在故事面板中添加,而是可以在單獨的用戶界面資源文件中創建界面。在Xcode中,這些文件是XIB文件
實現步驟如下:
- 創建一個新的Cocoa Touch Class,命名爲AboutViewController,並選中“Also create XIB file”
- 這時候多出了三個文件,將他們放到supporting files的上面
- 打開AboutViewController.xib,這是IB文件,不支持任何腳本功能,如segue何連接。使用Attributes檢查器將視圖的頂部欄設置爲不透明的導航欄,發現導航欄不能編輯
- 使用Lable或其他,自行添加內容
- 打開故事面板,添加一個About按鈕。位置看上面的圖。
- 在ViewController.m中import AboutViewController.h
- 將About拉到ViewController.h中創建action,名稱爲aboutCarValet
- aboutCarValet方法代碼如下:
- (IBAction)aboutCarValet:(id)sender {
AboutViewController *nextController;
nextController = [[AboutViewController alloc]initWithNibName:@"AboutViewController"//1
bundle:[NSBundle mainBundle]];
nextController.title = @"About CarValet";//2
[self.navigationController pushViewController:nextController animated:YES];
}
註釋:
- 爲AboutViewController實例初始化next Controller視圖控制器。該調用用到了之前爲視圖控制器界面創建的XIB文件
- 設置About視圖的標題。尅本地化該字符串
- 告訴導航控制器將新的視圖控制器推到對戰中——也就是打開並轉場到該場景
運行結果:
添加顏色
我們在IB中,有時候會看到Tint(色調)選項。使用此選項是爲用戶體驗增加彩色主題的快速方法。需要注意的是,它與VIew區域中改變背景色是不同的。
對UINavigationController來說,可以更改導航欄、工具欄和工具欄按鈕的色調。爲事物設置色調的工作由導航控制器進行管理,導航控制器會改變它管理的每個屏幕上該事物的顏色。
打開故事面板,自行修改顏色。
可能會遇到工具欄色調不起作用,那麼我們可以用代碼實現,在ViewController.m中的viewDidLoad方法下,添加
UIColor *sky = [UIColor colorWithDisplayP3Red:102.0/255.0 green:204.0/255.0 blue:255.0/255.0 alpha:1.0];
self.navigationController.toolbar.barTintColor = sky;
這時候顏色就添加完啦,本程序還添加了其他顏色,配色方案如下
用戶界面元素 | 蘋果蠟筆顏色 | RGB |
---|---|---|
工具欄 | SKY | R:102 G:204 B:255 |
標題 | snow(white) | R:255 G:255 B:255 |
按鈕 | Mocha | R:128 G:64 B:0 |
但是我們上面的方法只能更改一個屏幕裏面的顏色,以下代碼是更改全部,在AppDelegate.m文件中
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UIColor *Mocha = [UIColor colorWithDisplayP3Red:128.0/255 green:64.0/255.0 blue:0/255.0 alpha:1.0];
[[UIButton appearance]setTitleColor:Mocha forState:UIControlStateNormal];
[[UIBarButtonItem appearance] setTintColor:Mocha];
return YES;
}
其中,最後兩行是通過appearance protocol協議修改按鈕,工具欄按鈕顏色。
好了,導航控制器的使用就暫時介紹到這裏咯。
1 標籤欄控制器
本想找clock程序作爲用例的,模擬器上竟然沒有。換成健康
看到下面的健康數據,今天,數據來源這些選項了吧,這些是標籤欄,每個欄對應不同的功能,而且有的欄裏面還有多個屏幕。
工具欄的工作原理
使用UITabBarController時,每個功能區域或標籤欄都是根視圖,實際上,標籤欄控制器是應用程序真正的根視圖,簡單的畫一下。
標籤欄控制器使用如下三個主要類:
- UITabBarController管理標籤欄選項卡中顯示的視圖控制器,並且還管理標籤欄的用戶交換,包括選擇處理選中。如果存在5個以上選項卡,那麼會展示More按鈕。它也管理對額外選項卡的訪問,並且管理選項卡的重新排序。
- UITabBar是能呈現1至5個以上的選項卡的視圖。每個選項卡都代表應用程序中一個不同的根視圖。如果有5個以上的選項卡,那麼特殊的More標籤放置子在右邊
- UITabBarIter是標籤欄的單個選項卡,包括兩個屬性分別用於標題和圖像,以及一個屬性用來自定義圖像在被選中時的行爲。
爲CarValet添加標籤欄
圖片什麼的之前已經導入了
- 打開故事面板,選中下圖
- 選擇Editor|Embed In|Tab Bar Controller
(PS,運行到這裏,標籤欄中應該是隻有一個圖標,圓形的還是方形的晚了)
- 更換圖標
這時候是隻有一個選項卡的,我就不運行了。現在我們將car image場景添加爲第二個選項卡
- 從Add/View場景中刪除Car Images按鈕
從標籤欄拉到Car Images場景,從Relationship Segue類別中選擇視圖控制器。這是就添加上去了。
更換圖標
- 這時候運行程序,下面有兩個選項卡了(PS我這是完整版,不要在意這些細節。。。)
然而運行的時候發現reset沒用
進行以下步驟修改:
- 在編輯器中打開CarImageViewController.h文件,將resetZoomButton的類別改成UIButton
- 在iPhone故事面板中,選擇CarImageViewController並將一個正常的按鈕拖入到頂層視圖,改標題爲Reset Zoom
- 設置約束,到頂部爲系統默認,到後邊緣爲0
- 拖拽一個從該按鈕到.h文件中的resetZoomButton實例變量的關聯
- 拖拽一個從該按鈕到car image視圖中發送resetZoom消息的關聯
- 在與該按鈕相對應的Attributes編輯器中的Control部分,將默認值設置爲不可用
ok,運行程序就行啦。
最後一點,移動的Info
我們通過代碼的形式添加about到標籤欄
- 移除Add/View中的about按鈕
- 打開ViewController.m並刪除對AboutVIewController.h的引用,刪除aboutCarValet:方法以及在ViewController.h中的定義
- 打開AppDelegate.m,導入AboutVIewController.h的引用。然後修改代碼如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UIColor *Mocha = [UIColor colorWithDisplayP3Red:128.0/255 green:64.0/255.0 blue:0/255.0 alpha:1.0];
[[UIButton appearance]setTitleColor:Mocha forState:UIControlStateNormal];
[[UIBarButtonItem appearance] setTintColor:Mocha];
UITabBarController *tabBarController = (UITabBarController*)self.window.rootViewController;//1
//2
AboutViewController *aboutViewController = [[AboutViewController alloc]initWithNibName:@"AboutViewController"
bundle:[NSBundle mainBundle]];
UITabBarItem *aboutItem = [[UITabBarItem alloc]initWithTitle:@"About" //3
image:[UIImage imageNamed:@"tag"]
tag:0];
[aboutViewController setTabBarItem:aboutItem];//4
NSMutableArray *currentItems = [NSMutableArray arrayWithArray:tabBarController.viewControllers];//5
[currentItems addObject:aboutViewController];//6
[tabBarController setViewControllers:currentItems animated:NO];//7
return YES;
}
註釋:
- 獲得對標籤欄控制器的引用。
- 從XIB文件創建About視圖控制器
- 爲About場景創建一個標籤欄選項,並設置合適的標題和圖片
- 將About視圖控制器的tabBarItem設置爲新的標籤欄選項。標籤欄控制器會在設置標籤欄選項的時候尋找該屬性
- 基於那些由標籤欄控制器進行管理的視圖控制器,創建一個可變數組
- 將About場景添加到視圖控制器數組的結尾。標籤欄選項以數組中相同的順序顯示
在應用程序啓動時,以不帶動畫效果的方式更新選項卡數組。如果該操作是在應用程序因用戶行爲而運行時發生,那麼我們可能願意以動畫效果更新變化
好了運行程序,再次貼圖:
今天的介紹就到這裏咯
我的另一個博客站點:Arnold-你們好啊