感覺好多文章不是很全面,所以本文收集整合了網上的幾篇文章,感覺有互相補充的效果。
如果想下載源碼來看:http://code4app.com/search/searchbar 。本源碼與本文無關
1、searchBar
本例子實現布局:上面是一個navigationController,接下來一個searchBar,下面是tableView
searchBar這個控件就用來搜索tableView上的數據
[[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
UISearchDisplayController這個控件很強大,它初始化是基於searchBar的,里面有些效果很不錯,apple都封裝好了,並且可以很好的支持實時搜索,即我們只需要將搜索出來的數據重新賦給array(這個array用來存儲tableView數據),不需要reloadData,就會自動出來
其實reloadData也沒用,為什么呢?因為搜索出來的結果顯示在tableView上,該tableView並不是當前布局的那個tableView,而是另外一個,我猜測應該是UISearchDisplayController里面自帶的,所以不要混淆了
特別是在tableView代理方法里,有時候需要判斷代理方法傳入的tableView是否為當前布局的tableView,因為也有可能是UISearchDisplayController里自帶的,它們同樣會觸發代理方法
當點擊searchBar時,它會自動上移並且遮住navigationController
經過測試,如果上面是navigationBar,則searchBar不會移動,但如果是UINavigationController自帶過來的,則會上移覆蓋
往往有的時候都是UINavigationController自帶過來的,如果使用UISearchDisplayController,searchBar就會自動覆蓋,這個情況我試了很多次,包括新創建了一個navigationBar蓋在上面,但效果依然不好,對於這種情況,基於我目前的技術,只能舍棄UISearchDisplayController,單純的用UISearchBar了,雖然效果差了一些,但需要實現的功能照樣可以,比如實時搜索,除了重新賦值給array外,額外的操作就是需要reloadData了。
有時候點擊searchBar時,右側可能沒有出現‘cancel/取消’按鈕,這時需要調用下面的方法
- (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated
相信看方法名字就知道是做什么的了
來源:http://www.cnblogs.com/mobiledevelopment/archive/2011/08/04/2127633.html
效果如圖:
可以根據輸入的關鍵字,在TableView中顯示符合的數據。
圖中分組顯示和索引效果,前面的博文已經記錄,不再贅述。下面的例子是基於前文的基礎上修改的,所以文件名啥的,請參考前文。
第一步是在TableView上方添加一個Search Bar,這里有一點需要注意,必須先把TableView拖下來,留下空間放Search Bar,不要在Table View占滿屏幕的情況下把Search Bar拖到Table View頂部。區別在於,使用后面的方法,Search Bar是作為Table View的Header部分添加的,而前面的方法,Search Bar是獨立的。在添加索引功能時,如果作為Table View的Header添加,右側的索引會遮住Search Bar的右邊部分。Search Bar幾個常用屬性:
Placeholder是提示,就是hint屬性,Corretion是自動修正,一般設為NO,即不修正,Show Cancel Button是顯示取消按鈕,我這里勾選。選中Search Bar的情況下切換到Connections Inspector面板,delegate與File’s Owner建立連接(我們會在ViewController中支持UISearchBarDelegate協議)。與前面幾篇文章的例子相同,ViewController文件名為PDViewController.h和PDViewController.m。
第二步,添加Table View和Search Bar的Outlet.按住Control鍵,分別拖動Table View和Search Bar到PDViewController.h,添加Outlet
第三步,就是PDViewController代碼:
PDViewController.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#import <UIKit/UIKit.h> @interface PDViewController : UIViewController<UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate> @property (strong,nonatomic) NSDictionary *names; @property (strong,nonatomic) NSMutableDictionary *mutableNames; @property (strong,nonatomic)NSMutableArray *mutableKeys; //可變字典和可變數組,用於存儲顯示的數據,而不可變的字典用於存儲從文件中讀取的數據 @property (strong, nonatomic) IBOutlet UITableView *table; @property (strong, nonatomic) IBOutlet UISearchBar *search; -(void)resetSearch; //重置搜索,即恢復到沒有輸入關鍵字的狀態 -(void)handleSearchForTerm:(NSString *)searchTerm; //處理搜索,即把不包含searchTerm的值從可變數組中刪除 @end |
PDViewController.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
#import "PDViewController.h"
#import "NSDictionary+MutableDeepCopy.h"
@implementation PDViewController
@synthesize names=_names;
@synthesize mutableKeys=_mutableKeys;
@synthesize table = _table;
@synthesize search = _search;
@synthesize mutableNames=_mutableNames;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *path=[[NSBundle mainBundle] pathForResource:@"sortednames" ofType:@"plist"];
//取得sortednames.plist絕對路徑
//sortednames.plist本身是一個NSDictionary,以鍵-值的形式存儲字符串數組
NSDictionary *dict=[[NSDictionary alloc] initWithContentsOfFile:path];
//轉換成NSDictionary對象
self.names=dict;
[self resetSearch];
//重置
[_table reloadData];
//重新載入數據
}
- (void)viewDidUnload
{
[self setTable:nil];
[self setSearch:nil];
[super viewDidUnload];
self.names=nil;
self.mutableKeys=nil;
self.mutableNames=nil;
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//返回分組數量,即Array的數量
return [_mutableKeys count];
//
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([_mutableKeys count]==0) {
return 0;
}
NSString *key=[_mutableKeys objectAtIndex:section];
NSArray *nameSection=[_mutableNames objectForKey:key];
return [nameSection count];
//返回Array的大小
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section=[indexPath section];
//分組號
NSUInteger rowNumber=[indexPath row];
//行號
//即返回第section組,rowNumber行的UITableViewCell
NSString *key=[_mutableKeys objectAtIndex:section];
//取得第section組array的key
NSArray *nameSection=[_mutableNames objectForKey:key];
//通過key,取得Array
static NSString * tableIdentifier=@"CellFromNib";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:tableIdentifier];
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:tableIdentifier];
}
cell.textLabel.text=[nameSection objectAtIndex:rowNumber];
//從數組中讀取字符串,設置text
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if ([_mutableKeys count]==0) {
return 0;
}
NSString *key=[_mutableKeys objectAtIndex:section];
return key;
}
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return _mutableKeys;
//通過key來索引
}
-(void)resetSearch
{//重置搜索
_mutableNames=[_names mutableDeepCopy];
//使用mutableDeepCopy方法深復制
NSMutableArray *keyarr=[NSMutableArray new];
[keyarr addObjectsFromArray:[[_names allKeys] sortedArrayUsingSelector:@selector(compare:)]];
//讀取鍵,排序后存放可變數組
_mutableKeys=keyarr;
}
-(void)handleSearchForTerm:(NSString *)searchTerm
{//處理搜索
NSMutableArray *sectionToRemove=[NSMutableArray new];
//分組待刪除列表
[self resetSearch];
//先重置
for(NSString *key in _mutableKeys)
{//循環讀取所有的數組
NSMutableArray *array=[_mutableNames valueForKey:key];
NSMutableArray *toRemove=[NSMutableArray new];
//待刪除列表
for(NSString *name in array)
{//數組內的元素循環對比
if([name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location==NSNotFound)
{
//rangeOfString方法是返回NSRange對象(包含位置索引和長度信息)
//NSCaseInsensitiveSearch是忽略大小寫
//這里的代碼會在name中找不到searchTerm時執行
[toRemove addObject:name];
//找不到,把name添加到待刪除列表
}
}
if ([array count]==[toRemove count]) {
[sectionToRemove addObject:key];
//如果待刪除的總數和數組元素總數相同,把該分組的key加入待刪除列表,即不顯示該分組
}
[array removeObjectsInArray:toRemove];
//刪除數組待刪除元素
}
[_mutableKeys removeObjectsInArray:sectionToRemove];
//能過待刪除的key數組刪除數組
[_table reloadData];
//重載數據
}
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{//TableView的項被選擇前觸發
[_search resignFirstResponder];
//搜索條釋放焦點,隱藏軟鍵盤
return indexPath;
}
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{//按軟鍵盤右下角的搜索按鈕時觸發
NSString *searchTerm=[searchBar text];
//讀取被輸入的關鍵字
[self handleSearchForTerm:searchTerm];
//根據關鍵字,進行處理
[_search resignFirstResponder];
//隱藏軟鍵盤
}
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{//搜索條輸入文字修改時觸發
if([searchText length]==0)
{//如果無文字輸入
[self resetSearch];
[_table reloadData];
return;
}
[self handleSearchForTerm:searchText];
//有文字輸入就把關鍵字傳給handleSearchForTerm處理
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{//取消按鈕被按下時觸發
[self resetSearch];
//重置
searchBar.text=@"";
//輸入框清空
[_table reloadData];
[_search resignFirstResponder];
//重新載入數據,隱藏軟鍵盤
}
@end |
mutableDeepCopy深復制的方法在NSDictionary+MutableDeepCopy定義,參考iOS/Objective-C開發 字典NSDictionary的深復制(使用category)
3、Search Bar and Search DisplayController的實現
新建Navigation-based Project。打開.xib文件,拖一個Search Bar and Search DisplayController 對象到Table View對象上方,如下圖所示,選中File’s Owner ,打開Connections面板:

現在我們來創建Search Bar和SearchDisplay Controller的出口。打開Assistant Editor,按住ctrl鍵,將SearchDisplay Controller拖到ViewController 的頭文件中。創建一個名為searchDisplayController的出口,然后點Connect。

同樣的方法為Search Bar創建連接。現在ViewController的頭文件看起來像這樣:
|
|
#import <UIKit/UIKit.h> @interface RootViewController : UITableViewController { UISearchDisplayController *searchDisplayController; UISearchDisplayController *searchBar; NSArray *allItems; NSArray *searchResults; } @property (nonatomic, retain) IBOutlet UISearchDisplayController *searchDisplayController; @property (nonatomic, retain) IBOutlet UISearchDisplayController *searchBar; @property (nonatomic, copy) NSArray *allItems; @property (nonatomic, copy) NSArray *searchResults; @end |
你可能注意到,我初始化了兩個NSArray。一個用於作為數據源,一個用於保存查找結果。在本文中,我使用字符串數組作為數據源。繼續編輯.m文件前,別忘了synthesize相關屬性:
|
|
@synthesize searchDisplayController; @synthesize searchBar; @synthesize allItems; @synthesize searchResults; |
在viewDidLoad 方法中,我們構造了我們的字符串數組:
|
|
- (void)viewDidLoad { [super viewDidLoad]; // [self.tableView reloadData]; self.tableView.scrollEnabled = YES; NSArray *items = [[NSArray alloc] initWithObjects: @"Code Geass", @"Asura Cryin'", @"Voltes V", @"Mazinger Z", @"Daimos", nil]; self.allItems = items; [items release]; [self.tableView reloadData]; } |
在Table View的返回TableView行數的方法中,我們先判斷當前Table View是否是searchDisplayController的查找結果表格還是數據源本來的表格,然后返回對應的行數:
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSInteger rows = 0; if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]){ rows = [self.searchResults count]; }else{ rows = [self.allItems count]; } return rows; } |
在tableView:cellForRowAtIndexPath:方法里,我們需要做同樣的事:
|
|
// Customize the appearance of table view cells. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } /* Configure the cell. */ if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]){ cell.textLabel.text = [self.searchResults objectAtIndex:indexPath.row]; }else{ cell.textLabel.text = [self.allItems objectAtIndex:indexPath.row]; } return cell; } |
現在來實現當搜索文本改變時的回調函數。這個方法使用謂詞進行比較,並講匹配結果賦給searchResults數組:
|
|
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope { NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", searchText]; self.searchResults = [self.allItems filteredArrayUsingPredicate:resultPredicate]; } |
接下來是UISearchDisplayController的委托方法,負責響應搜索事件:
|
|
#pragma mark - UISearchDisplayController delegate methods -(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { [self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]]; return YES; } - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption { [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]]; return YES; } |
運行工程,當你在搜索欄中點擊及輸入文本時,如下圖所示:

4、UISearchBar的使用以及下拉列表框的實現
在IOS混飯吃的同志們都很清楚,搜索框在移動開發應用中的地位。今天我們就結合下拉列表框的實現來聊聊UISearchBar的使用。本人新入行的菜鳥一個,不足之處請多多指教。直接上代碼。
UISearchBar控件的聲明:(在控制器DownListViewController中)
- @property (nonatomic,retain) UISearchBar* searchBar;
控件的初始化:
- _searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 320, 40)];
- _searchBar.placeholder = @"test"; //設置占位符
- _searchBar.delegate = self; //設置控件代理
當然,做完這些工作之后,我們還要在將控件添加到父視圖之上,也可以把他設置成UITableView的tableHeaderView屬性值,由於大家需求不一,這里就不再給出代碼。
前面,我們設置了控件的代理,當然我們必須讓控制器(DownListViewController)的 .h 文件實現 UISearchBarDelegate 協議,然后我們繼續, 我們要在 .m 文件中實現協議方法:
- #pragma mark -
- #pragma mark UISearchBarDelegate
- //搜索框中的內容發生改變時 回調(即要搜索的內容改變)
- - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
- NSLog(@"changed");
- if (_searchBar.text.length == 0) {
- [self setSearchControllerHidden:YES]; //控制下拉列表的隱現
- }else{
- [self setSearchControllerHidden:NO];
- }
- }
- - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
- searchBar.showsCancelButton = YES;
- for(id cc in [searchBar subviews])
{
if([cc isKindOfClass:[UIButton class]])
{
UIButton *btn = (UIButton *)cc;
[btn setTitle:@"取消" forState:UIControlStateNormal];
}
} - NSLog(@"shuould begin");
- return YES;
- }
- - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
- searchBar.text = @"";
- NSLog(@"did begin");
- }
- - (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
- NSLog(@"did end");
- searchBar.showsCancelButton = NO;
- }
- - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
- NSLog(@"search clicked");
- }
- //點擊搜索框上的 取消按鈕時 調用
- - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
- NSLog(@"cancle clicked");
- _searchBar.text = @"";
- [_searchBar resignFirstResponder];
- [self setSearchControllerHidden:YES];
- }
至此,搜索框的實現就搞定了,怎么樣簡單吧。下面我們來講講下拉列表框的實現,先說說他的實現原理或者是思路吧。下拉列表框我們用一個控制器來實現,我們新建一個控制器SearchViewController.
- @interface SearchViewController : UITableViewController
- @end
在 .m 文件中,我們實現該控制器
- - (id)initWithStyle:(UITableViewStyle)style
- {
- self = [super initWithStyle:style];
- if (self) {
- // Custom initialization
- }
- return self;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.tableView.layer.borderWidth = 1;
- self.tableView.layer.borderColor = [[UIColor blackColor] CGColor];
- }
然后實現控制器的數據源,
- #pragma mark -
- #pragma mark Table view data source
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
- return 1;
- }
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- // 返回列表框的下拉列表的數量
- return 3;
- }
- // Customize the appearance of table view cells.
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
- }
- // Configure the cell...
- NSUInteger row = [indexPath row];
- cell.textLabel.text = @"down list";
- return cell;
- }
這樣列表框的控制器就實現了。接下來我們就來看看怎么讓出現、隱藏。這點我們利用UIView的動畫效果來實現,我們在DownListViewController控制器中 增加一個方法:
- - (void) setSearchControllerHidden:(BOOL)hidden {
- NSInteger height = hidden ? 0: 180;
- [UIView beginAnimations:nil context:nil];
- [UIView setAnimationDuration:0.2];
- [_searchController.view setFrame:CGRectMake(30, 36, 200, height)];
- [UIView commitAnimations];
- }
我們只需調用該方法就可以了。現在我們看看DownListViewController的布局方法
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- _searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 320, 40)];
- _searchBar.placeholder = @"test";
- _searchBar.delegate = self;
- _tableview = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
- _tableview.dataSource = self;
- _tableview.tableHeaderView = _searchBar;
- _searchController = [[SearchViewController alloc] initWithStyle:UITableViewStylePlain];
- [_searchController.view setFrame:CGRectMake(30, 40, 200, 0)];
- [self.view addSubview:_tableview];
- [self.view addSubview:_searchController.view];
- }
這樣一切都搞定了。
好了,總結一下:
我們用了兩個控制器:DownListViewController(搜索框的實現 和 控制下拉列表框的出現與隱藏)和SearchViewController(下拉列表框的實現)。在DownListViewController中我們聲明並初始化 UISearchBar和SearchViewController(高度開始設置為零),用動畫來實現下拉列表框的出現與隱藏。
本文出自 “開發問道” 博客,請務必保留此出處http://izhuaodev.blog.51cto.com/6266344/1102408

