一、基本使用
UISearchController 在ios 8系统之后就可以使用了,原来使用UISearchBar+UISearchDisplayController实现搜索的传统方式建议废弃。前面刚做了一个项目,有用到UISearchController,并且过程中遇到一些坑,所以在这儿分享总结一下。
一般的需求是:ViewControllerA 有一个tableView用于展示数据,点击搜索栏之后,搜索结果的数据源和ViewControllerA的数据源是一样,只是用NSPredicate过滤一下。展示也是用的ViewControllerA的tableView。这个其他很多人写了demo,可以随便搜一下UISearchController的基本用法。
现在有这样一种需求。ViewControllerA的数据源和页面展示都是独立的。搜索结果页面,搜索根据searchBar的关键字,另外调接口获取数据并展示。
正好,UISearchController 有这样一个方法:可以传入一个展示结果的resultViewController。
// Pass nil if you wish to display search results in the same view that you are searching. This is not supported on tvOS; please provide a results controller on tvOS.
- (instancetype)initWithSearchResultsController:(nullable UIViewController *)searchResultsController;
如果你想在原来的页面展示搜索结果,就直接传nil。如果你想用另外一个VC展示搜索结果,就传入你自定义的resultVC。
CACSearchResultViewController *ctr = [[CACSearchResultViewController alloc] init];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:ctr];
self.searchController.delegate = ctr;
self.searchController.searchResultsUpdater = ctr;
在这儿将UISearchController的代理和更新代理都指定为resultVC。
@interface CACSearchResultViewController ()<UISearchResultsUpdating, UISearchControllerDelegate,UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
然后resultVC要实现UISearchControllerDelegate和UISearchResultUpdating协议。这里有一点要注意的是,你项目跑起来之后,还是看不见resultVC的页面,因为,UISearchController会默认隐藏resultVC的view。你看到的还是ViewControllerA的页面。不过要注意的是,UISearchController其实也有一个View,默认情况下这个View的背景色是透明的,resultVC的view其实是加在UISearchController的View上的 。再额外说一下,此时的resultVC和ViewControllerA不在同一个navigationContoler的堆栈里。这两个VC的切换是通过UISearchController控制的。如果你在resultVC中想通过navigationController push一个新的VC,就会报错。因为resultVC的navigationController是nil。于是,在resultVC.m里面,要手动设置self.view.hidden = NO。
#pragma mark- UISearchControllerDelegate
- (void)didPresentSearchController:(UISearchController *)searchController {
self.view.hidden = NO;
}
- (void)willDismissSearchController:(UISearchController *)searchController {
self.view.hidden = YES;
}
在页面出现时,将self.view.hidden设置为NO;页面消失的时候,设置为YES。这样才能看到resultVC的页面。然后是对searchBar的监听,通过实现下面这个方法,来监听searchBar的变化。但是这个方法不太好用,当searchBar成为firstResponer也会响应。也就意味着键盘弹出和收缩,都会触发这个方法,所以不在这个方法里做数据请求。而且,每次触发这个方法,都会将resultVC的View隐藏掉。所以,在updateSearchResultsForSearchController方法中,也要手动设置resultVC.view.hidden = NO。
@protocol UISearchResultsUpdating <NSObject>
@required
// Called when the search bar's text or scope has changed or when the search bar becomes first responder.
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController;
@end
更好的办法是,监听searchBar里关键字的改变,当内容发生改变,才发起网络请求。在updateSearchResultsForSearchController中,将searchController的searchBar强引用。就可以获取到resultVC的searchBar了。通过实现UISearchBarDelegate中的方法,可以对搜索栏进行监听。
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText; // called when text changes (including clear)
到这里,基本上整个项目运行起来的效果就可以看到了。
二、坑点
1.在设置searchController的属性时,一般配置这三个。要注意的是,第二个是IOS 9才支持。
@property (nonatomic, assign) BOOL dimsBackgroundDuringPresentation __TVOS_PROHIBITED; // default is YES, and has the same behavior as obscuresBackgroundDuringPresentation.
@property (nonatomic, assign) BOOL obscuresBackgroundDuringPresentation NS_AVAILABLE_IOS(9_1); // default is YES
@property (nonatomic, assign) BOOL hidesNavigationBarDuringPresentation; // default is YES
2.问题描述:设置了自动隐藏navigationBar之后,搜索结果页面顶部透明。如图:
问题原因:前面有提到,resultVC的view加在UISearchController的view上,而UISearchController的View默认是透明的,所以就能看到背后ViewControllerA的内容。
解决方案:设置UISearchController.view.backgroundColor = 背景色;
3.问题描述:在ios8的机器上运行时,resultVC的view会向上移动64,并且能看到ViewControllerA的底部内容。如图:
问题原因:不详...
解决办法:在resultVC的页面出现时,强行修改frame,使其显示正常。
笔者也是新手,对遇到的问题可能部分理解不是特别准确或者有什么错误,请多多指教。