引言
下面我們來學(xué)習(xí)比xib更強(qiáng)大的SB
如何理解SB?
最簡單的理解就是:一個.storyboard文件相當(dāng)于多個基于VC使用的.xib文件恩商,由此我們可以看出,SB(只能基于VC,不能基于View),我們有多個VC的類是可以和一個SB文件建立關(guān)系的听系,使用方法:
SecVC *secVC = [[UIStoryboard storyboardWithName:@"Demo" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"SecVC"];
之前的一天一點(diǎn)xib:2初識xib有過介紹, 通過這個方法,我們傳入不同VC的identifier虹菲,就會得到不同的VC對象靠胜。
為什么是強(qiáng)大了?
xib可以基于View毕源、VC甚至自己獨(dú)立的使用髓帽,而SB只能基于VC使用,為什么說比xib更加強(qiáng)大呢脑豹?主要是下面的兩個原因:
1.SB支持segue
2.SB對cell的支持更加強(qiáng)大
什么是segue?
想象我們點(diǎn)擊一個VC中的button后跳轉(zhuǎn)到另一個VC的場景衡查,通常用的都是navigationController的push瘩欺,或者present一個模態(tài)視圖,即使有xib的情況下,要完成跳轉(zhuǎn)其實(shí)也不簡單俱饿,要把按鈕拖到@implementation中實(shí)現(xiàn)一個IBAction的方法歌粥,然后在里面寫上:
[self.navigationController pushViewController:Sec animated:YES]
或者
[self presentViewController:Sec animated:YES completion:nil]
要想簡化這個沒有技術(shù)含量的過程,就要用到SB的segue拍埠。
我們在一個VC中選擇要發(fā)生跳轉(zhuǎn)的按鈕失驶,按control拖動到另一個VC上就會出現(xiàn)一個菜單,在菜單上你就可以選擇跳轉(zhuǎn)的方式push枣购、present嬉探,這樣不用寫一行代碼就能完成頁面間的跳轉(zhuǎn),而兩個VC之間的像紐扣一樣用線連著兩個VC的的東西就是segue棉圈,是一個UIStoryboardSegue對象涩堤,我們可以簡單的理解成是完成頁面跳轉(zhuǎn)相關(guān)功能的一個類,是不是很簡單分瘾?
segue雖然簡單胎围,如何傳參?
我們知道用SB的segue來實(shí)現(xiàn)也頁面跳轉(zhuǎn)十分方便德召,但是如果要向跳轉(zhuǎn)的頁面?zhèn)鲄⒃撛趺崔k白魂?
假設(shè)我們要點(diǎn)擊ViewController這個VC里的一個按鈕,跳轉(zhuǎn)到SecVC這個VC中上岗,把testTitle這個參數(shù)傳過去福荸。第一步還是要選中按鈕,拖到SecVC里液茎,然后選中這個segue逞姿,給它一個id值,確保用代碼可以找到它捆等,然后在ViewController中編碼:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"sec"]) {
SecVC *secVC = (SecVC *)segue.destinationViewController;
secVC.testTite = @"hello world";
}
}
設(shè)置SB中segue的identifier滞造,主要就是要在這里使用,因?yàn)槎鄠€button發(fā)生的多個頁面跳轉(zhuǎn)都是回調(diào)這個函數(shù)栋烤,所以要用identifier來區(qū)分是哪個segue谒养,跳哪個頁面,傳哪些參數(shù)明郭。
id的sender就是觸發(fā)跳轉(zhuǎn)的那個button或其他控件买窟。
不確定的跳轉(zhuǎn)如何使用segue?
一下場景經(jīng)常出現(xiàn):甲VC中有個button薯定,點(diǎn)擊后有可能跳轉(zhuǎn)到乙頁面始绍,也可能跳轉(zhuǎn)的丙頁面,怎么解话侄?
我們假設(shè)我們要點(diǎn)擊ViewController這個VC里的一個按鈕亏推,有可能要跳到SecVC学赛,有可能要跳thirdVC。
1.在SB中準(zhǔn)備segue吞杭。
注意我們這次創(chuàng)建的segue的方式并不是選中button按control拖到另一個VC中盏浇,而是選中VC,右鍵選中triggered segues里manual后面的+拖動到另一個VC里芽狗,這個很重要绢掰,而且還是要給segue一個id。
2.編碼實(shí)現(xiàn)跳轉(zhuǎn):
- (IBAction)testSegue:(id)sender
{
BOOL flag = NO;
if (flag) {
[self performSegueWithIdentifier:@"sec" sender:sender];
} else {
[self performSegueWithIdentifier:@"third" sender:sender];
}
}
代碼實(shí)現(xiàn)segue跳轉(zhuǎn)也很簡單:
- (void)performSegueWithIdentifier:(NSString *)identifier sender:(nullable id)sender
第一個參數(shù)是segue的id童擎,第二個參數(shù)是觸發(fā)這個跳轉(zhuǎn)的控件滴劲。
在segue跳轉(zhuǎn)頁面的過程中還會調(diào)一個函數(shù),我們可以重寫這個函數(shù)柔昼,來決定是否讓這個跳轉(zhuǎn)發(fā)生哑芹。eg:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
if (_islogin) {
return YES;
} else {
NSLog(@"您還沒有登錄,請先登錄"); //用log舉個例子
return NO;
}
}
更靈活的segue
如果你熟練掌握了segue他其實(shí)可以做很多事情捕透,其實(shí)segue并不僅僅能完成跳轉(zhuǎn)聪姿,還有一類segue叫做relationship segue,之前是幫助大家理解乙嘀,所以說的比較簡單末购,其實(shí)我們選中一個NavigationController按control鍵拖動到另一個VC上的話也可以生成segue,我們選中root view controller虎谢,就將Nav的rootViewController屬性設(shè)置成了這個VC盟榴,這個segue就是relationship segue,同樣婴噩,拖動一個tabbarController也會出現(xiàn)viewControllers的relationship segue擎场。
更好的使用Cell
用xib的時候,要想用cell几莽,通常是建立一個cell子類迅办,一個與之對應(yīng)的.xib文件。用SB的時候要想用cell就簡單的多了章蚣,因?yàn)閏ell是可以直接拖動到tableView里的站欺,直接在tableView里管理cell設(shè)置屬性,當(dāng)然如果是復(fù)雜的cell還是要子類話對應(yīng)的.h纤垂、.m的矾策。
SB在使用cell分兩種情況:1靜態(tài)cell,2動態(tài)cell峭沦。
靜態(tài)cell
設(shè)置靜態(tài)cell:
注意靜態(tài)cell一定要基于UITableViewController贾虽,否則會報錯。
展示靜態(tài)cell的tableView是不用調(diào)用自己必須實(shí)現(xiàn)的datasource協(xié)議的
你會很驚訝吼鱼,為什么必須調(diào)用的datasource協(xié)議都不用實(shí)現(xiàn)榄鉴?答案是靜態(tài)履磨,靜態(tài)的cell,意義就在于你在xib中設(shè)置成什么樣庆尘,他就展現(xiàn)什么樣,不會再調(diào)用datasource向你要cell了巷送,因?yàn)樵赟B文件中已經(jīng)確定下來了驶忌。
在做一些“死”頁面的時候SB的靜態(tài)cell是很好的選擇,靜態(tài)cell也不是什么都不能做笑跛,靜態(tài)cell里的button還是可以拖到@implementation中形成IBAction的付魔,但是是無法生成IBOutlet屬性或字段的。
即使你強(qiáng)行的給一個靜態(tài)的cell指定了一個cell的類飞蹂,也是無法向其內(nèi)部拖入IBOutlet的几苍。這就是靜態(tài)cell的局限性,但是如果你要設(shè)置的數(shù)據(jù)不多還是可以考慮用靜態(tài)cell陈哑,因?yàn)槟憧梢酝ㄟ^給cell上的控件設(shè)tag來找到它從而賦值妻坝。
動態(tài)cell的使用
在上圖中設(shè)置content屬性為Dynamic Prototypes就可以了。使用動態(tài)cell的話就要在VC中實(shí)現(xiàn)那兩個必須實(shí)現(xiàn)的datasource協(xié)議了惊窖,下面舉個簡單的例子:
1.給cell指定一個class
2.給cell設(shè)置id刽宪,重用機(jī)制使用,其他屬性就不詳細(xì)說明了界酒,和其他控件的屬性差不多圣拄。
3.給cell添加一些控件,并拖到TestCell源文件中生成IBOutlet的屬性毁欣,在VC中實(shí)現(xiàn)那兩個必須實(shí)現(xiàn)的協(xié)議方法:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TestCell *testCell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:@"testCell"];
testCell.testLabel.text = @"hello world";
return testCell;
}
這里注意庇谆,不需要在tableView:cellForRowAtIndexPath:中創(chuàng)建cell了,這是與xib使用cell最大的區(qū)別凭疮,下面是xib使用cell的方法舉例:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TestCell *testCell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:@"testCell"];
if (!testCell) {
testCell = [[NSBundle mainBundle] loadNibNamed:@"TestCell" owner:self options:nil];
}
testCell.testLabel.text = @"hello world";
return testCell;
}
這是很重要的饭耳,千萬記住,因?yàn)槲覀兪侵苯油蟘ell到SB文件的tableView里的哭尝,所以直接從重用池里取就好了哥攘。
這里稍微提一個地方:我們這里取重用cell用的是函數(shù):
dequeueReusableCellWithIdentifier:,而系統(tǒng)中還有另一個重用的函數(shù):dequeueReusableCellWithIdentifier:forIndexPath:這個函數(shù)比我們代碼中用的那個好材鹦,是我們用的那個api的優(yōu)化版逝淹,它是iOS6引入的api,完全符合我們一般app對版本兼容的要求桶唐,這里感謝簡書用戶coderzcj在評論中給我留言栅葡,謝謝你。我后續(xù)會再寫一篇文章專門說說系統(tǒng)對xib優(yōu)化的事情的尤泽,非常感謝大家的支持欣簇。
總結(jié)
SB的segue和cell使用是它最大意義的地方规脸,當(dāng)然之前xib能做的設(shè)置,SB也都能做熊咽,而且多個.xib對應(yīng)一個SB文件莫鸭,使文件量變少了不少,但是如果想單獨(dú)用View的地方還是要用xib横殴。
歡迎大家和我交流溝通被因,若文章中有錯誤和紕漏,懇請指正衫仑,謝謝梨与。