下面,我們來(lái)演示一下如何在Tab Bar項(xiàng)目基礎(chǔ)上添加一個(gè)搜索欄。通過(guò)搜索欄,App可以讓用戶(hù)指定搜索條件后,搜索菜單列表。
?
1.理解搜索欄顯示控制器(Search Display Controller)
?
你可以使用搜索顯示控制器(如 UISearchDisplayController 類(lèi))管理App中的搜索功能。搜索顯示控制器管理搜索欄(search bar)和表視圖(table view)的顯示,表視圖復(fù)雜顯示搜索結(jié)果。
?
當(dāng)用戶(hù)開(kāi)始搜索時(shí),搜索顯示控制器將在原始的視圖之上,疊加搜索界面,并顯示搜索結(jié)果。有趣的是,在表視圖中顯示的結(jié)果是有搜索顯示控制器生成的。
?
和其它的視圖控制器一樣,你可以選擇編程創(chuàng)建搜索控制器,或者使用Storyboard簡(jiǎn)單添加搜索顯示控制器到App中,我們采用后者。
?
2.在Storyboard 中添加搜索顯示控制器
?
在Storyboard 編程界面,拖拉Search Bar and Search Display Controller 對(duì)象到 Recipe Book 視圖控制器的導(dǎo)航條下面。如果操作正確,你應(yīng)該看到的如下所示的界面:
?
?
?在繼續(xù)之前,我們嘗試運(yùn)行下App,界面效果如下。在沒(méi)有編寫(xiě)任何新的代碼之前,你已經(jīng)有一個(gè)搜索欄。輕拍搜索欄,將顯示搜索界面。但是,搜索并沒(méi)有顯示正確的搜索結(jié)果。
?
3.搜索結(jié)果顯示原理解析?
?
在前面提到過(guò),搜索結(jié)果顯示搜索顯示控制器(Search Display Controller)生成的表視圖中,
?
我們?cè)陂_(kāi)發(fā)視圖App時(shí),我們實(shí)現(xiàn)了UITableViewDataSource協(xié)議,告訴表視圖有多少條數(shù)據(jù)行顯示,以及每一行的數(shù)據(jù)。
?
和UITableView 對(duì)象一樣,搜索顯示控制器生成的表視圖采用相同的方法,采用委托的方式,讓搜索欄和搜索結(jié)果交互。
?
?
一般而言,原始視圖控制器作為搜索結(jié)果數(shù)據(jù)源和委托的源對(duì)象,我們不必手動(dòng)連接數(shù)據(jù)源(DataSource)和委托(Delegate)到視圖控制器上,
?
當(dāng)我們插入搜索欄到Recipe Book 視圖控制器中時(shí),將自動(dòng)建立搜索顯示控制器(Search Display Controller)的連接。鼠標(biāo)右鍵,點(diǎn)擊搜索顯示控制器(Search Display Controller)顯示連接信息。
?
兩個(gè)表視圖(Recipe Book 視圖控制器中的表視圖 ?和 搜索結(jié)果表視圖)共享相同的視圖控制器,負(fù)責(zé)數(shù)據(jù)填充。在顯示表數(shù)據(jù)時(shí),都會(huì)調(diào)用到
?
?
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{}
?
和
?
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {}
?
4.實(shí)現(xiàn)搜索過(guò)濾器
?
顯然,為了實(shí)現(xiàn)搜索功能,我們必須實(shí)現(xiàn)如下任務(wù):
?
1.實(shí)現(xiàn)方法過(guò)濾菜單名稱(chēng),返回正確的搜索結(jié)果
2.更改數(shù)據(jù)源方法,區(qū)分不同的表視圖。如果傳入的tableView 是 Recipe Book 視圖控制器的表視圖,則顯示所有的菜單列表,如果傳入的是搜索結(jié)果表視圖,則僅僅顯示搜索結(jié)果。
?
首先,我們演示如何時(shí)間過(guò)濾器,這里,我們已經(jīng)有一個(gè)數(shù)組存放所有的菜單列表了,我們需要?jiǎng)?chuàng)建另外一個(gè)數(shù)組存放搜索結(jié)果 - 命名為searchResults 數(shù)組。
?
?
@implementation RecipeBookViewController
{
? ? NSArray *recipes;
? ? NSArray *searchResults;
}
- ( void )filterContentForSearchText:( NSString *)searchText scope:( NSString *)scope
{
? ? NSPredicate *resultPredicate = [ NSPredicate predicateWithFormat : @"SELF contains[cd] %@" ,searchText];
? ? searchResults = [ recipes filteredArrayUsingPredicate :resultPredicate];
}
?
基本上,一個(gè)Predicate,返回Boolearn值(true或false).你可以NSPredicate格式指定查詢(xún)條件,然后使用NSPredicate對(duì)象過(guò)濾數(shù)組中的數(shù)據(jù)。NSArray提供了filteredArrayUsingPredicate:方法,該方法返回一個(gè)新的數(shù)組,數(shù)組包含了匹配制定的Predicate的對(duì)象。Predicate 中 SELF 關(guān)鍵字 - SELF contains[cd]%@ 指向比較對(duì)象(如菜單名稱(chēng))。
?
操作符[cd]表示比較操作 - case 和 diacritic 不敏感。
?
?
?
5.實(shí)現(xiàn)搜索顯示控制器(Search Display Controller)委托
?
現(xiàn)在,我們已經(jīng)創(chuàng)建了處理數(shù)據(jù)過(guò)濾的方法,但是如何調(diào)用該方法呢?
?
顯然,在用戶(hù)輸入搜索條件時(shí),調(diào)用filterContentForSearchText: 方法。
?
UISearchDisplayController 類(lèi)提供了 shouldReloadTableForSearchString: 方法,在搜索文本更改時(shí),該方法會(huì)自動(dòng)調(diào)用,因此,在RecipeBookViewController.m 文件添加如下方法:
?
?
- ( BOOL )searchDisplayController:( UISearchDisplayController *)controller shouldReloadTableForSearchString:( NSString *)searchString
{
? ? [ self filterContentForSearchText :searchString scope :[[ self . searchDisplayController . searchBar scopeButtonTitles ] objectAtIndex :[ self . searchDisplayController . searchBar selectedScopeButtonIndex ]]];
? ? return YES ;
}
?
?
6.在searchResultsTableView 顯示搜索結(jié)果
?
在前面解釋過(guò),我們需要修改Data Source 方法,區(qū)分不同的表視圖(如Recipe Book 視圖控制器中的表視圖 ?和 搜索結(jié)果表視圖)。
?
區(qū)分表視圖是相當(dāng)簡(jiǎn)單的。
?
我們簡(jiǎn)單標(biāo)記tableView 對(duì)象和 searchDisplayController的 searchResultsTableView.?
?
如果相同,則顯示搜索結(jié)果。
?
代碼修改如下:
?
?
- ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section
{
? ? if (tableView == self . searchDisplayController . searchResultsTableView ) {
? ? ? ? return [ searchResults count ];
? ? } else {
? ? ? ? return [ recipes count ];
? ? }
}
?
?
?
?
- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath
{
? ? static NSString *simpleTableIdentifier = @"RecipeCell" ;
?
? ? UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier :simpleTableIdentifier];
?
? ? if (cell == nil ) {
? ? ? ? cell = [[ UITableViewCell alloc ] initWithStyle : UITableViewCellStyleDefault reuseIdentifier :simpleTableIdentifier];
? ? }
?
? ? if (tableView == self . searchDisplayController . searchResultsTableView ) {
? ? ? ? cell. textLabel . text = [ searchResults objectAtIndex :indexPath. row ];
? ? } else {
? ? ? ? cell. textLabel . text = [ recipes objectAtIndex :indexPath. row ];
?
? ? }
?
? ? return cell;
}
- ( void )tableView:( UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath
{
? ? if (tableView == self . searchDisplayController . searchResultsTableView ) {
? ? ? ? [ self performSegueWithIdentifier : @"showRecipeDetail" sender : self ];
? ? }
}
?
我們簡(jiǎn)單的調(diào)用preformSegueWithIdentifier: 方法,手動(dòng)觸發(fā)showRecipeDetail 聯(lián)線。
?
在繼續(xù)編寫(xiě)代碼之前,我們?cè)俅芜\(yùn)行App。在你選擇任一搜索結(jié)果記錄時(shí),App顯示詳細(xì)視圖,并帶有菜單名稱(chēng),
?
但是,菜單名稱(chēng)并不總是正確的。
?
參考prepareForSegue: 方法,我們使用indexPathForSelectedRow 方法檢索所選indexPath屬性值。
?
前面提到過(guò),搜索結(jié)果顯示在一個(gè)獨(dú)立的表視圖中,但是,在之前的prepareForSegue:方法中,我們總是從Recipe Book
?
視圖控制器的表視圖中檢索所選中的記錄行。
?
這就是為什么我們?cè)谠敿?xì)視圖中獲得錯(cuò)誤的菜單名稱(chēng)。為了取得搜索結(jié)果中正確的選擇,我們需要修改prepareForSegue:方法:
?
?
- ( void )prepareForSegue:( UIStoryboardSegue *)segue sender:( id )sender
{
? ? if ([segue. identifier isEqualToString : @"showRecipeDetail" ]) {
?
? ? ? ? NSIndexPath *indexPath = nil ;
?
? ? ? ? RecipeDetailViewController *destViewController = segue. destinationViewController ;
? ? ? ? if ([ self . searchDisplayController isActive ]) {
? ? ? ? ? ? indexPath = [ self . searchDisplayController . searchResultsTableView indexPathForSelectedRow ];
? ? ? ? ? ? destViewController. recipeName = [ searchResults objectAtIndex :indexPath. row ];
? ? ? ? } else {
? ? ? ? ? ? indexPath = [ self . tableView indexPathForSelectedRow ];
? ? ? ? ? ? destViewController. recipeName = [ recipes objectAtIndex :indexPath. row ];
? ? ? ? }
?
? ? }
}

?
?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
