一篇较为详细的 Storyboard使用方法 总结
Storyboard是蘋果官方主推的一個代替xib的策略。有必要詳細學習下它的使用方法。
先來看一下思維導圖
storyboard_28
storyboard基礎
storyboard優勢
storyboard能代替nib自然有其優勢,一般來說storyboard具有以下幾種優點:
- storyboard能將nib匯總統一管理
- storyboard可以描述各種場景之間的過渡,這種過渡被稱作segue,storyboard 把 view controller叫做:scene,可以通過拖拽實現過度,減少代碼
- 支持tableview的prototype cell,可以在storyboard中編輯cell,減少代碼量
storyboard的基本使用
啟動storyboard
加載storyboard肯定是需要一個主入口的,這個主入口在info.plist中:
storyboard_1
初始化ViewController
確定了哪個storyboard是主入口,那顯然也要確定哪個ViewController是storyboard的主入口。需要選中相應ViewController,勾選Is Initial View Controller
storyboard_2
此時,對應ViewController前出現一個箭頭
storyboard_3
創建relationship segue
對于三大container view controller,即Tab Bar Controller,Navigation Controller,Split View Controller ,可以通過拖拽創建設置relationship segue。
如下圖的 popup menu 是從tab bar controller 連到navigation controller,松手后的彈出:
storyboard_4
連接后的圖標如下圖,表示relationship segue
storyboard_5
命名tabbar controller的tabbar
并非在tabbar controller里,而是在與其相連、對應的controller里改動,如圖:
storyboard_6
navigation bar 的 title 也是同理。但是,強烈不建議在storyboard里設置navigationbar,因為storyboard是為了簡化操作的,但是設置navigationbar太麻煩了,還不如代碼方便實用。
設置ViewController對應的類
選中相應ViewController,然后在 Custom Class 內寫上相應類名即可。注意,要選中 ViewController 而不是其中的 View,要點擊圖中的黃色圓形按鈕。
storyboard_7
獲取視圖控制器
就是通過UITableViewController和UINavigationController中的viewControllers獲取:
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController; UINavigationController *navigationController = [tabBarController viewControllers][0]; PlayersViewController *playersViewController = [navigationController viewControllers][0];Prototype cells
選中tableview,設置tableview的 cotent 為 Dynamic Propotype
storyboard_8
一般在tableView: cellForRowAtIndexPath:方法中都像下面:
但是,由于在storyboard中已經創建了cell,那么就可以直接使用了:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PlayerCell"];// Configure the cell...return cell; } 當然,一個tableview里肯定不應該只有一個,可以把上面的 Content 下面的 Prototype Cells 增加cell,然后選擇任意cell,如圖:
storyboard_9
設置不同的 identifier 來標識不同的cell。
除了在viewcontroller里直接創建cell,不需要另一個cell的xib的區別外,其他方面和xib無異。也可以選中cell,在右邊欄指定對應的Controller的custom class用來控制cell。同樣的,也不能直接把cell中的view連線到cell所屬的viewController中。
Static cells
使用靜態的cell,適用在僅有幾個確定cell的tableview中,不能重用,設置了幾個cell,就顯示幾個cell。static cells的設置如下圖:
storyboard_10
因為prototype cells究竟怎么顯示可以在代碼中設置,所以只需要設置有幾個可重用的cell就行了,而static cells因為不可重用,那么這里的設置選項就變成了 Sections 設置多少段。
那么怎么設置每個section有多少個cell呢?選中如下圖所示的只有static cells才有的藍色立方體:
storyboard_11
此時右邊欄出現如圖所示 Table View Section
storyboard_12
可以設置數量,表頭表尾的title
和 prototype cell 一樣,static cell可以指定一個專門的Controller。但是不同的是,static cell 的cell以及cell中的控件都相當于確定的view,因此,static cell可以把cell以及cell中的控件連線到cell所屬的viewController中。
也就是說,如果在cell的Controller中設置了一個button的點擊事件,然后又在cell所屬viewController中又設置了一次該button的點擊事件,不會報錯,兩個點擊事件都會觸發。
所以,方便起見,static cell 直接在viewController中連線設置就可以了。
使用segue
簡介
什么是Segue
Storyboard上每一根用來界面跳轉的線,都是一個UIStoryboardSegue對象(簡稱Segue)
Segue的屬性
每一個Segue對象,都有3個屬性
// 唯一標識 @property (nonatomic, readonly) NSString *identifier; // 來源控制器 @property (nonatomic, readonly) id sourceViewController; // 目標控制器 @property (nonatomic, readonly) id destinationViewController;Segue的類型
根據Segue的執行(跳轉)時刻,Segue可以分為2大類型:
- 自動型(Action segue):點擊某個控件后(比如按鈕),自動執行Segue,自動完成界面跳轉。
- 手動型(Manual segue):需要通過寫代碼手動執行Segue,才能完成界面跳轉。
segue執行過程
手動調用performSegueWithIdentifier:sender:方法實現跳轉。那么這期間發生了什么呢?大致分為三個部分。
其實就是執行了UIStoryboardSegue中initWithIdentifier:source:destination:方法,并且identifier就是在Storyboard中Segue屬性設置的標識. 來源就是連線的頭部. 目標就是連線尾
所謂跳轉前的準備,因為可以拿到Segue(來源控制器,目標控制器),所以就可以在這里給下一個控制器傳遞數據。這個方法是系統默認調用,所以只需要實現即可。另外,只能由來源控制器調用,來拿到目標控制器。
頁面跳轉
segue可以實現頁面間跳轉,除了上面的 relationship segue 還有 Action segue 和 Manual segue,分別對應button跳轉和viewController跳轉。
跳進
使用storyboard
Action segue 比較簡單,就是將button連到要展示的viewController上,當點擊時,就會觸發。
Manual segue 相對比較麻煩,但是比較靈活。它設置了兩個viewController的跳轉關系,在你需要的時候出發跳轉。
首先,先對兩個viewController進行連線:
storyboard_14
之后點擊連線后兩個viewController之間產生的箭頭,在右邊欄可以看到如下:
storyboard_15
其中參數?identifier?就是跳轉的標識符,根據這個標識符來確定跳轉到是那個頁面。下面幾個參數,下面再說。
接下來就可以調用方法,在合適的時機加載了
//根據 segue Identifier跳轉界面 [self performSegueWithIdentifier:@"GotoTwo" sender:self];其中的identifer自然不用多說,那么sender是什么呢?sender是參數名稱,理論上可以指代任何對象,用來區分是哪個控件觸發了segue。比如有兩個button都跳轉到一個頁面,那么這時就可以設置sender區分了。引申開來,在設置button點擊事件時的-(IBAction)click:(id)sender;方法中的sender和這里的sender是一個作用。
使用純代碼
上面的方法實現效果和平時用的下面兩個方法相同:
//以modal 方式跳轉 [self presentViewController:ViewController animated:YES completion:nil]; //壓進一個viewcontroller [self.navigationController pushViewController:ViewController animated:YES completion:nil]; 不過,既然用了storyboard了,那么實例化viewController時就不能用initWithNibName了。在storyboard中,要通過storyboard找到viewController的布局。首先要設置viewcontroller的 storyboardID:
storyboard_19
那個use storyboardId的勾不打也行,不知道干什么用的,
現在就可以在代碼中找到特定storyboard的viewcontroller了:
- (IBAction)tapButton:(id)sender {//獲取storyboard: 通過bundle根據storyboard的名字來獲取我們的storyboard,UIStoryboard *story = [UIStoryboard storyboardWithName:@"Main" bundle:nil];//由storyboard根據myView的storyBoardID來獲取我們要切換的視圖UIViewController *myView = [story instantiateViewControllerWithIdentifier:@"myView"];//顯示ViewController[self presentViewController:myView animated:YES completion:nil]; }跳出
能跳進當然也要能跳出,可以使用 exit segue 跳轉至任意連線的位置,也可以使用代碼跳轉。
exit segue
跳出和跳進的方法類似,略有區別,比如要從界面2跳轉回界面1:
先打開需要返回到的界面ViewController1.m,加上下面方法,返回類型一定是IBAction,參數類型一定是UIStoryboardSegue,名稱隨便(這個方法一定要加,返回時調用的)
//其他界面返回到此界面調用的方法 - (IBAction)ViewController1UnwindSegue:(UIStoryboardSegue *)unwindSegue { } 右鍵2界面上方的Exit(下圖中畫綠圈的)彈出菜單中可以看到剛才在1界面中加的那個方法的名稱(下圖中紅色圈里),然后如下圖一樣連線,彈出菜單選擇manual,這里連接自己表示要在當前viewcontroller中用代碼的方式回退。
storyboard_17
給2視圖的unwind segue取一個名字叫from2to1的identifier如下圖:
storyboard_18
現在就可以在界面2中的任意時候調用方法回退了:
- (IBAction)back:(id)sender {//執行segue跳頁的方法[self performSegueWithIdentifier:@"from2to1" sender:nil]; }使用的仍是跳進時用的方法,不過第一步的操作已經告訴xcode這是一個回退操作了。可以從上圖看到,這個 Unwind Segue 綁定了回退到的界面的一個方法,因此,執行跳轉后會執行綁定的方法:
//其他界面返回到此界面調用的方法 - (IBAction)ViewController1UnwindSegue:(UIStoryboardSegue *)unwindSegue {if ([unwindSegue.identifier isEqualToString:@"from2to1"]) {_lbShowMessage.text = @"從2退到1";} else if ([unwindSegue.identifier isEqualToString:@"from3to1"]) {_lbShowMessage.text = @"從3退到1";} }這里就看出上面為什么說類型一定是UIStoryboardSegue了,因為可以接收一個該類型的對象,以此判斷是從哪個頁面的回退。
使用 exit segue 的好處是可以跳轉到任意打開過的界面比如從3->1,而不是只能返回上級界面從2->1。
一般跳出方法
也可以使用代碼根據是model類型還是push類型選擇:
//彈出一個viewcontroller 相當與返回上一個界面 [self.navigationController popViewControllerAnimated:YES]; // 以 modal跳轉的返回方法 [self dismissViewControllerAnimated:YES];跳轉的方式
在進行跳轉連線后會出現如下窗口:
storyboard_13
共有三種跳轉方式,也就是上面右邊欄的Kind屬性
push
Push類型必須用在NavigationController中,否則報錯。是在navigation View Controller中下一級時使用的那種從右側劃入的方式。
model
最常用的場景,新的場景完全蓋住了舊的那個。用戶無法再與上一個場景交互,除非他們先關閉這個場景。可以在右邊欄的Presentation選擇需要展示的動畫效果。
custom
自定義類型,需要繼承UIStoryboardSegue類,然后重寫Perform方法,然后在Storyboard上將類設置為自定義的類。
storyboard_16
這段代碼的作用是創建從中心漸變充滿屏幕的動畫:
其實實質還是presentViewController,但是不用系統帶的animation,而是先將destinationViewController的頁面用動畫加載后,直接present。
跳轉傳值
前面說到,- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender方法會在跳轉時自動觸發。跳轉傳值就在這個方法內完成。
我們可以對Segue的標識進行判斷,一般有以下兩種方法:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {if ([segue.identifier isEqual: @"login2index"]) {// 需要執行的代碼} } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {if ([segue.destinationViewController isKindOfClass:[IndexTableViewController class]]) {// 執行代碼} }第一種需要在設置標識的值,并且匹配。第二種卻是通過目標控制器判斷。個人感覺還是第一種靠譜一些。
接下來就可以對destination進行賦值了:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {NSLog(@"觸發該場景切換的sender對象的類型是:%@",[sender class]);//方法一,使用KVC給B 也就是目標場景傳值UIViewController *destinationController=[segue destinationViewController];[destinationController setValue:@"119" forKey:@"number"];//方法2,使用屬性傳值,需導入相關的類.h//BViewController *bController=[segue destinationViewController];//bController.number=@188; }跳轉傳值不僅可以用prepareForSegue:sender:實現,也可以通過代理、通知的方式,不過這樣挺麻煩的,不推薦。具體參見使用storyboard實現頁面跳轉,簡單的數據傳遞
多分支NavigationController
主要應用在下面這種情況:
storyboard_20
navigationController要分情況跳轉到界面A或者界面B,但是navigationController只能有一個rootViewController啊。所以,通過一個空的ParentViewController在viewWillAppear:方法中加載任意一個ChildViewController。如下圖:
storyboard_22
注意,上圖紅框中的分支,其實表現的只是一個頁面的兩種形態,本質上還是一個頁面。所以加載childViewController的segue都要用不帶任何動畫的custome類型。因為如果ChildViewController有動畫,那么就會暴露出ParentViewController中的空白部分,就表現為兩個頁面了。
可以看出,這個方法的優點是可以通過parent,從C1直接跳到C2,如果不用這種父子ViewController的方式,那么不可避免的就得先從C1跳回前一級頁面,然后再從前一級頁面跳到C2。不過缺點就是C1到C2的跳轉沒有任何跳轉動畫。
不過,思考了一段時間后,覺得多分支NavigationController本身并不是一個問題,用父子ViewController的方式雖然能解決,但是把問題復雜化了。比如應用在登錄跳轉上,我完全可以不用在加載NavigationController后再判斷是否要登錄,而是把這一過程放到加載NavigationController之前。至于可以直接跳轉的這一好處,一般情況下,產品也不會這么設計,而且它的弊端也是很明顯的。
具體實現的過程參見基于Storyboard的創建多分支NavigationController的方法。記得如果使用這種方法的話,一定要清除Parent中上次顯示的ChildViewController,文中在prepareForSegue:sender:方法中清除,是個很好的時機。?
storyboard reference
iOS9中,蘋果引入了 storyboard reference 用以減小storyboard的體積,方便管理(并不知道iOS9之前怎么用多個storyboard)。
簡化現有storyboard
如下圖,是做上面練習時創建的一個storyboard,界面已經有點多了。可以使用storyboard reference簡化,將一部分viewcontroller拆分到其他storyboard里。
storyboard_23
做法其實很簡單,選中想要拆分的viewcontroller,然后在菜單欄干中“Editor->Refactor to Storyboard”,如下圖所示。然后命名新的storyboard即可。
storyboard_24
storyboard_25
加載storyboard中一個特定viewController
和拖拽其他控件一樣,找到storyboard控件,拖拽到storyboard上:
storyboard_26
然后設置storyboard:
storyboard_27
這里面storyboard填的是目標storboard的文件名;Reference ID是啥?從它的提示也就才出來了,用來確定聯結的是那個viewController,填的是目標storyboard中目標viewController的Storyboard ID,具體在哪設,上面也說過。
這樣,一個簡潔的storyboard就能創建出來了。
參考鏈接
【Storyboard】Storyboard介紹及使用
UIStoryboardSegue講解;
iOS-prepareForSegue場景切換,KVC傳值;
(4.4.1)使用storyboard實現頁面跳轉,簡單的數據傳遞;
【iOS界面處理】使用storyboard實現頁面跳轉,簡單的數據傳遞
iOS9 Day-by-Day :: Day 3 :: Storyboard References;
基于Storyboard的創建多分支NavigationController的方法;
iOS 9 Storyboard 教程(一下);
10 Practical Tips for iOS Developers Using Storyboards;
還有一些看完隨手就關了,沒有記錄。
本人的處女篇。iOS菜鳥,水平有限,如有錯誤,多多指正~
總結
以上是生活随笔為你收集整理的一篇较为详细的 Storyboard使用方法 总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷P2071 座位安排
- 下一篇: 使用安卓模拟器时提示关闭hyper-v