前记
UISearchDisplayController
是iOS开发中专门为UITableView
提供搜索而封装的一个类,平时开发的时候也没怎么用到,这次趁着项目开发中用到它,做了下笔记,方便下次再次用到的时候查找方便。
UISearchDisplayController介绍
UISearchDisplayController
是用来提供搜索展示的,兼容3.0~8.0
,8.0
之后就过期了,被UISearchController
所取代,这次主要讲如何使用UISearchDisplayController
以及在使用中碰到的一些问题,先来看下项目中结合UISearchDisplayController
做搜索是一个怎样的效果,先上图!
整体的动画效果很流畅,如果是我们自己来做这个动画,估计也不容易,接下来我们来看看项目中如何使用UISearchDisplayController
吧!
UISearchDisplayController使用
UISearchDisplayController
的使用场景是UITableView
+UISearchBar
+带有UINavigationController结构的UIViewController
,这些东西如何创建我就不啰嗦了,直奔主题吧!
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
| - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.title = @"Apple"; _contentArray = [[NSMutableArray alloc] initWithObjects:@"iPhone",@"iPod",@"iPod touch",@"iPad",@"iPad mini",@"iMac",@"Mac Pro",@"MacBook Air",@"MacBook Pro", nil]; _contentTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; _contentTableView.dataSource = self; _contentTableView.delegate = self; [self.view addSubview:_contentTableView]; [self addSearchBar]; }
- (void)addSearchBar { _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
_contentTableView.tableHeaderView = _searchBar;
_searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self]; _searchDisplayController.searchResultsDataSource = self; _searchDisplayController.searchResultsDelegate = self; _searchDisplayController.delegate = self; }
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (tableView == _contentTableView) { return [_contentArray count]; } else { NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self contains [cd] %@",_searchDisplayController.searchBar.text]; _filterData = [[NSArray alloc] initWithArray:[_contentArray filteredArrayUsingPredicate:predicate]]; return _filterData.count; } }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellStr = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellStr]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellStr]; } if (tableView == _contentTableView) { cell.textLabel.text = [_contentArray objectAtIndex:[indexPath row]]; } else { cell.textLabel.text = [_filterData objectAtIndex:[indexPath row]]; } return cell;
}
|
简单的代码就能使用UISearchDisplayController
,代码里面用到了NSPredicate
,这个有点类似正则表达,是用来过滤结果使用的,具体的介绍请移步到此NSPredicate介绍,接下来我们来玩点高级的。
UISearchDisplayController高级用法
使用自定义的搜索界面
如果觉得系统提供的搜索结果界面无法满足项目需求,需要自定义的时候,我们就需要使用到UISearchDisplayController
的delegate了,它提供了很多了委托方法,请自行查看UISearchDisplayDelegate
,这里就不一一列举了,在自定义搜索界面的时候,我用到了其中3个回调,暂时能满足需求了
1 2 3 4 5 6
| //搜索动画即将开始的时候回调 - (void) searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller NS_DEPRECATED_IOS(3_0,8_0); //搜索动画即将结束的时候回调 - (void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller NS_DEPRECATED_IOS(3_0,8_0); //显示搜索结果的回调 - (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView NS_DEPRECATED_IOS(3_0,8_0);
|
具体的实现方案如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| - (void) searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller NS_DEPRECATED_IOS(3_0,8_0) { _searchResultController = [[SearchResultViewController alloc] init]; [controller.searchContentsController addChildViewController:_searchResultController]; [controller.searchContentsController.view addSubview:_searchResultController.view]; [controller.searchContentsController.view bringSubviewToFront:_searchResultController.view]; }
- (void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller NS_DEPRECATED_IOS(3_0,8_0) { if (_searchResultController) { [_searchResultController.view removeFromSuperview]; [_searchResultController removeFromParentViewController]; _searchResultController = nil; } }
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView NS_DEPRECATED_IOS(3_0,8_0) { tableView.hidden = YES; }
|
上面这些代码就能实现去掉系统自带的搜索结果界面,而使用自定义的搜索界面了。这代码有很多优化的地方,我这边只是介绍实现方案,具体项目具体处理,优化方案就不再这里讨论了。
去掉半透明遮罩
如果上面我们使用了自定义的搜索界面,但是有个很可恶的东西,就是在还没搜索前有个半透明的遮罩(这个半透明遮罩有人觉得好,有人觉得不好,主要是看项目需求,我的项目里面不需要用它,所以要把它去掉),界面上不是特别美观,所以就要想方设法把它去掉。
一开始本来还想通过寻找委托函数来实现该方案,但是都没能找到一个适合的(也许我找的有问题,如果能通过委托函数来实现的,麻烦告知一下,我也学习下),最后发现UISearchDisplayController
有个这样的函数
1
| - (void)setActive:(BOOL)visible animated:(BOOL)animated;
|
它是在用户点击UISearchBar
做收起动画的时候以及用户点击Cancel
按钮的时候都会触发的,我们可以直接在该函数里面实现我们去掉半透明遮罩的功能,具体方案如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| - (void)setActive:(BOOL)visible animated:(BOOL)animated { if(self.active == visible) { return; } [super setActive:visible animated:animated]; NSArray *subViews = self.searchContentsController.view.subviews; if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f) { for (UIView *view in subViews) { if ([view isKindOfClass:NSClassFromString(@"UISearchDisplayControllerContainerView")]) { NSArray *sub = view.subviews; ((UIView*)sub[2]).hidden = YES; } } } else { [[subViews lastObject] removeFromSuperview]; } }
|
实现后再次点击UISearchBar
的时候:
半透明遮罩消失了,大功告成!
最后整个工程的代码已经上传到Github上,大家可以到这里下载,有任何问题,欢迎讨论。