UISearchBar和 UISearchDisplayController的使用

来源:互联网 发布:html标签id使用js变量 编辑:程序博客网 时间:2024/05/17 08:56

UISearchBar和 UISearchDisplayController的使用

感觉好多文章不是很全面,所以本文收集整合了网上的几篇文章,感觉有互相补充的效果。

如果想下载源码来看: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

2、iOS开发 给TableView增加SearchBar

效果如图:

可以根据输入的关键字,在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:

123456789101112131415
#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:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
#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中)

  1. @property (nonatomic,retain) UISearchBar* searchBar; 

控件的初始化:

  1. _searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 320, 40)]; 
  2. _searchBar.placeholder = @"test";   //设置占位符 
  3. _searchBar.delegate = self;   //设置控件代理 

当然,做完这些工作之后,我们还要在将控件添加到父视图之上,也可以把他设置成UITableView的tableHeaderView属性值,由于大家需求不一,这里就不再给出代码。

前面,我们设置了控件的代理,当然我们必须让控制器(DownListViewController)的 .h 文件实现 UISearchBarDelegate 协议,然后我们继续, 我们要在 .m 文件中实现协议方法:

  1. #pragma mark - 
  2. #pragma mark UISearchBarDelegate 
  3.  
  4. //搜索框中的内容发生改变时 回调(即要搜索的内容改变)
  5. - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{ 
  6.     NSLog(@"changed"); 
  7.     if (_searchBar.text.length == 0) { 
  8.         [self setSearchControllerHidden:YES]; //控制下拉列表的隐现
  9.     }else{ 
  10.         [self setSearchControllerHidden:NO]; 
  11.   
  12.     } 
  13. - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar { 
  14.     searchBar.showsCancelButton = YES; 
  15. for(id cc in [searchBar subviews])
    {
    if([cc isKindOfClass:[UIButton class]])
    {
    UIButton *btn = (UIButton *)cc;
    [btn setTitle:@"取消" forState:UIControlStateNormal];
    }
    }
  16.     NSLog(@"shuould begin"); 
  17.     return YES; 
  18.  
  19. - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar { 
  20.     searchBar.text = @""; 
  21.     NSLog(@"did begin"); 
  22.  
  23. - (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar { 
  24.     NSLog(@"did end"); 
  25.     searchBar.showsCancelButton = NO; 
  26.  
  27.  
  28. - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { 
  29.     NSLog(@"search clicked"); 
  30.  
  31. //点击搜索框上的 取消按钮时 调用
  32. - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { 
  33.     NSLog(@"cancle clicked"); 
  34.     _searchBar.text = @""; 
  35.     [_searchBar resignFirstResponder]; 
  36.     [self setSearchControllerHidden:YES]; 

至此,搜索框的实现就搞定了,怎么样简单吧。下面我们来讲讲下拉列表框的实现,先说说他的实现原理或者是思路吧。下拉列表框我们用一个控制器来实现,我们新建一个控制器SearchViewController.

  1. @interface SearchViewController : UITableViewController 
  2.  
  3. @end 

在 .m 文件中,我们实现该控制器

  1. - (id)initWithStyle:(UITableViewStyle)style 
  2.     self = [super initWithStyle:style]; 
  3.     if (self) { 
  4.         // Custom initialization 
  5.     } 
  6.     return self; 
  7.  
  8. - (void)viewDidLoad 
  9.     [super viewDidLoad]; 
  10.  
  11.     self.tableView.layer.borderWidth = 1; 
  12.     self.tableView.layer.borderColor = [[UIColor blackColor] CGColor]; 
  13.  

然后实现控制器的数据源,

 

  1. #pragma mark - 
  2. #pragma mark Table view data source 
  3.  
  4. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {  
  5.     return 1; 
  6.  
  7.  
  8. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
  9.     // 返回列表框的下拉列表的数量 
  10.     return 3; 
  11.  
  12.  
  13. // Customize the appearance of table view cells. 
  14. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
  15.      
  16.     static NSString *CellIdentifier = @"Cell"; 
  17.      
  18.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
  19.     if (cell == nil) { 
  20.         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ; 
  21.     } 
  22.      
  23.     // Configure the cell... 
  24.     NSUInteger row = [indexPath row]; 
  25.     cell.textLabel.text = @"down list"; 
  26.      
  27.     return cell; 

这样列表框的控制器就实现了。接下来我们就来看看怎么让出现、隐藏。这点我们利用UIView的动画效果来实现,我们在DownListViewController控制器中 增加一个方法:

  1. - (void) setSearchControllerHidden:(BOOL)hidden { 
  2.     NSInteger height = hidden ? 0: 180; 
  3.     [UIView beginAnimations:nil context:nil]; 
  4.     [UIView setAnimationDuration:0.2]; 
  5.      
  6.     [_searchController.view setFrame:CGRectMake(30, 36, 200, height)]; 
  7.     [UIView commitAnimations]; 

我们只需调用该方法就可以了。现在我们看看DownListViewController的布局方法

  1. - (void)viewDidLoad 
  2.     [super viewDidLoad]; 
  3.     _searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 320, 40)]; 
  4.     _searchBar.placeholder = @"test"; 
  5.     _searchBar.delegate = self;  
  6.      
  7.     _tableview = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain]; 
  8.     _tableview.dataSource = self; 
  9.     _tableview.tableHeaderView = _searchBar; 
  10.      
  11.     _searchController = [[SearchViewController alloc] initWithStyle:UITableViewStylePlain]; 
  12.     [_searchController.view setFrame:CGRectMake(30, 40, 200, 0)]; 
  13.      
  14.     [self.view addSubview:_tableview]; 
  15.     [self.view addSubview:_searchController.view]; 

这样一切都搞定了。

 

好了,总结一下:

我们用了两个控制器:DownListViewController(搜索框的实现 和 控制下拉列表框的出现与隐藏)和SearchViewController(下拉列表框的实现)。在DownListViewController中我们声明并初始化 UISearchBar和SearchViewController(高度开始设置为零),用动画来实现下拉列表框的出现与隐藏。

本文出自 “开发问道” 博客,请务必保留此出处http://izhuaodev.blog.51cto.com/6266344/1102408

0 0
原创粉丝点击