您的当前位置:首页searchBar

searchBar

2024-12-13 来源:哗拓教育

1、searchBar

本例子实现布局:上面是一个navigationController,接下来一个searchBar,下面是tableView

searchBar这个控件就用来搜索tableView上的数据

[[UISearchDisplayControlleralloc] initWithSearchBar:searchBarcontentsController: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

相信看方法名字就知道是做什么的了

效果如图:

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

15#import

@interface PDViewController : UIViewController

@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:

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

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

@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...

NSUIntegerrow = [indexPath row];

cell.textLabel.text = @"down list";

return cell;

}

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

- (void) setSearchControllerHidden:(BOOL)hidden {

NSIntegerheight =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];

}

显示全文