小说网站 搜小说 无限网 烟雨红尘 小说爱好者 免费小说 免费小说网站

UISearchController替换UISearchDisplayController

随着iOS 的升级,iOS 7的占有率更低了。Xcode 升级到Xcode 8之后,对iOS 应用支持的最低版本,iOS 7也被抛弃了。我在新项目中也是最低支持到iOS 8,因此工程里也是各种警告。首先看到的就是UISearchDisplayController建议替换为UISearchController

以前的搜索功能回顾

以前我们要在表格头部加一个搜索功能是这样写的:

    //解决搜索栏在取消时,抖动问题。
    [self setAutomaticallyAdjustsScrollViewInsets:YES];
    [self setExtendedLayoutIncludesOpaqueBars:YES];
    //设置搜索框
    UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 44)];
    searchBar.delegate = self;
    searchBar.placeholder = @"精确搜索:通过昵称或手机号码";
    searchBar.tintColor = kThemeColor;
    self.searchDisplayVC = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
    self.searchDisplayVC.searchResultsDataSource = self;
    self.searchDisplayVC.searchResultsDelegate = self;
    self.searchDisplayVC.searchResultsTableView.rowHeight = 64;
    UIView *view = [UIView new];
    view.backgroundColor = [UIColor clearColor];
    self.searchDisplayVC.searchResultsTableView.tableFooterView = view;

    self.tableView.tableHeaderView = searchBar;
    self.tableView.rowHeight = 50;
    self.tableView.tableFooterView = [UIView new];

可以看到,如果我们要在表格头部加一个搜索框,需要初始化UISearchBar和UISearchDisplayController,还需要设置一堆东西。还是挺麻烦的!

然后就是要实现,UISearchBar的一个代理方法(当然我们可以实现UISearchDisplayController的代理方法):

#pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    [self.searchArray removeAllObjects];
    // 这里是搜索操作
    NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"self contains[cd] %@",_searchController.searchBar.text];
    self.searchArray = [[self.titles filteredArrayUsingPredicate:searchPredicate] mutableCopy];
    //刷新搜索表格
    [_searchDisplayVC.searchResultsTableView reloadData];
}

然后tableView 的数据源代理也需要区分是否为搜索表格

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (tableView == _tableView) {
        return _titles.count;
    }

    return _searchArr.count;
}

新的搜索功能实现

iOS 8以后,苹果推荐使用UISearchController,如果在初始化的时候,没有设置searchResultsController,那么搜索结果就在代理对象控制器的表格中显示。

    _searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    _searchController.searchResultsUpdater = self;
    // 默认为YES,控制搜索控制器的灰色半透明效果
    //    _searchController.dimsBackgroundDuringPresentation = NO;
    // 默认为YES,控制搜索时,是否隐藏导航栏
    //    _searchController.hidesNavigationBarDuringPresentation = NO;
    _searchController.searchBar.delegate = self;
    _searchController.searchBar.placeholder = @"请输入...";
    _searchController.searchBar.tintColor = [UIColor orangeColor];
    _searchController.searchBar.barTintColor = [UIColor greenColor];
    [_searchController.searchBar sizeToFit];

    self.definesPresentationContext = YES;

    self.tableView.tableHeaderView = _searchController.searchBar;

    self.tableView.tableFooterView = [UIView new];

接下来也是实现代理方法:

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
    [self.searchArray removeAllObjects];
    //执行搜索操作
    NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"self contains[cd] %@",_searchController.searchBar.text];
    self.searchArray = [[self.titles filteredArrayUsingPredicate:searchPredicate] mutableCopy];
    //刷新表格
    [self.tableView reloadData];
}

因为搜索结果和正常情况使用的是同一个tableView,那么如何区分搜索时显示搜索的数据源呢?
通过UISearchController的active属性即可判断,这是一个BOOL类型的属性。
示例代码:

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (_searchController.active) {
        return self.searchArray.count;
    }
    return self.titles.count;
}

其实到这里,表格头部的搜索功能就完成了。

下面还有一些可能出现的Bug或场景解决方案。

1.如果我不需要实时显示搜索结果怎么处理?

显然,如果我们搜索功能的结果需要服务器返回,那么就不应该在用户输入每个字母的时候都去请求一次。应该是用户输入完关键字,点击搜索后再去搜索。
那么这时,就需要先实现UISearchBar 的UISearchBarDelegate中的代理方法:

#pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    [self.searchArray removeAllObjects];
    //执行搜索操作
    NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"self contains[cd] %@",_searchController.searchBar.text];
    self.searchArray = [[self.titles filteredArrayUsingPredicate:searchPredicate] mutableCopy];
    //刷新表格
    [self.tableView reloadData];
}

然后,还必须实现的UISearchControllerUISearchResultsUpdating中的代理方法:

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
    //刷新表格
    [self.tableView reloadData];
}

可以看一下上面这个代理方法的注释:

// Called when the search bar's text or scope has changed or when the search bar becomes first responder.
当搜索框中的内容,范围发生变化,或者搜索框成为或者取消第一响应者时,会被调用。

所以需要在这里刷新一下tableView 来更新数据源,因为他们用的是同一个tableView展示数据。
怎么证明呢?
很简单,只需要在tableView 的数据源方法中打印一下tableView,看他们是否是同一个TableView对象即可。

// 正常情况下的tableView
<UITableView: 0x7f86aa113000; frame = (0 0; 320 504); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x600000241c20>; layer = <CALayer: 0x6000000354c0>; contentOffset: {0, 0}; contentSize: {320, 0}>

// 搜索输入框被激活时的tableView
<UITableView: 0x7f86aa113000; frame = (0 0; 375 603); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x600000241c20>; layer = <CALayer: 0x6000000354c0>; contentOffset: {0, 0}; contentSize: {375, 3344}>

2.设置搜索栏背景色

直接上代码了:

    _searchController.searchBar.barTintColor = [UIColor greenColor];

当然,在以前的实现方式里,也可以直接设置searchBar的barTintColor来修改搜索栏的背景色。(这个属性是iOS 7之后加的)

3.改变搜索栏 “取消”按钮和 光标的颜色

还是直接上代码:

_searchController.searchBar.tintColor = [UIColor orangeColor];

4.使用UISearchController如何在搜索时将搜索栏移动到导航栏上

这个问题的解决方案需要设置两个地方:
第一,确保UISearchController 的hidesNavigationBarDuringPresentation为YES(这个属性默认就是YES,你要确定你没修改过这个属性)。
第二,将当前控制器的definesPresentationContext设置为YES。即:

self.definesPresentationContext = YES;

posted on 2016-09-30 14:53  王小航  阅读(1582)  评论(0编辑  收藏  举报

导航