UISearchController使用指南(Swift)

2016.07.03


引言

拖延了大半年最终还是决定老老实实走上写blog的不归路,正好最近在用swift重构项目中的搜索页面,使用了UISearchController(iOS 8.0 & later),在使用过程中发现一些需要注意的地方,且感觉现在网上对UISearchController使用的介绍普遍不清晰或者过于简单,遂决定拿它开刀,作为人生第一篇blog的主角。
本文尽量从工程实际使用价值的角度来介绍UISearchController,且提供一份示例项目代码,欢迎留言讨论。


概述

首先需要说明的是,UISearchController的使用场景有一定限制,概括来说,目前只有以下两个场景下在工程使用中的可实现性得到了验证,其他使用场景基本都存在专场动画等方面的bug,如果你知道还有其他的实现场景,欢迎留言。

1.在UITableView的tableHeaderView中使用,实现类似微信首页搜索的场景

ForTableHeaderView.gif

2.在NavigationBar的titleView上使用,实现类似淘宝首页搜索的场景,这种场景可以做适当的衍生,实现navigationBarItem来触发搜索界面,但归根结底还是基于此种场景,故不再拿出单独讨论

ForNavigationBar.gif

基本设置

个人感觉UISearchController在工程中最大的意义应该在于可以轻松完成MVC解耦,将一个相对复杂的搜索Scene解耦成一个主MVC+一个子MVC。子MVC可以专注实现进入搜索状态时响应逻辑和页面展示等工作,而只需要在创建UISearchController时将子MVC的Controller设置为searchResultsController即可完成关联。而对于简单的搜索场景,如果只想在同一个MVC中完成搜索功能,只需将searchResultsController参数传入nil,并将UISearchController.searchResultsUpdater代理设置为当前MVC。

注意:


使用UISearchController时当前UIViewController有一个很重要的属性:definesPresentationContext,对应用场景一,应设置为false,防止出现细微的动画异常(真的很细微,不仔细看看不出来);对场景二,则必须设置为true,但是在当前页面willDisappear时,应将其设置回默认的false状态,否则可能对其他页面产生异常


以下基本设置按实际需求调整:

searchController = UISearchController(searchResultsController: searchResultsVC)

searchController.searchBar.frame = CGRectMake(0, 0, view.bounds.width, 44)

searchController.hidesNavigationBarDuringPresentation = true
searchController.dimsBackgroundDuringPresentation = true

searchController.searchResultsUpdater = searchResultsVC
searchController.delegate = self
searchController.searchBar.delegate = self

在这里介绍两个坑


一号坑:

searchBar.tintColor会同时改变光标的颜色,所以,如果当你在期望改变按钮颜色为白色时,光标就看不到了
解决方案:
单独设置searchBar的按钮颜色,这里因为当年swift没有支持可变参数函数,所以在iOS8时代没有对应的方法,需要用OC封装一下然后swift调用OC

if #available(iOS 9.0, *) {
    //此方法仅对9.0之后版本生效
    UIBarButtonItem.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).tintColor = UIColor.whiteColor()
} else {
    //对9.0之前版本需桥接OC版对UIBarButtonItem的扩展
    UIBarButtonItem.my_appearanceWhenContainedIn(UISearchBar.self).tintColor = UIColor.whiteColor()
}
二号坑:

searBar默认控制在输入为空时键盘上搜索按钮不可点击,但是在向searchBar中粘贴字符串或者代码控制直接像searchBar.text赋值,键盘上的搜索按钮会依然处于失效状态,此bug疑似由UISearchController内部机制引起
解决方案:
A.关闭searBar输入为空时自动将搜索按钮置失效,但需要根据需求自己控制输入为空时是否允许触发搜索

searchController.searchBar.enablesReturnKeyAutomatically = false

B.在向searchBar中粘贴字符串或者代码控制直接向searchBar.text赋值时,对searchBar先resignFirstResponder再becomeFirstResponder
通过代码控制直接向searchBar.text赋值时此方案已得到验证,如何捕获粘贴字符串动作本人目前未能实现,故尚未验证,但是从前者的表现来看应该是可以的


代理实现

需要实现
1.UISearchBarDelegate
实现对键盘点击搜索等动作的响应

//MARK: UISearchBarDelegate
extension SearchControllerForTableHeaderViewController: UISearchBarDelegate {
    func searchBarSearchButtonClicked(searchBar: UISearchBar) {
        //点击键盘上的搜索按钮时执行此代理,可按实际需求进行处理
        print("didClickSearchBuuton")
    }
}

2.UISearchControllerDelegate
控制在进入/离开搜索状态时需要调整的设置和UI等

//MARK: UISearchControllerDelegate
extension SearchControllerForTableHeaderViewController: UISearchControllerDelegate {
    func willPresentSearchController(searchController: UISearchController) {
        //若需要在无输入时亦展示searchResultsController.view,需执行此句,必须在主线程中执行
        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            searchController.searchResultsController!.view.hidden = false;
        }
    }
    
    func didPresentSearchController(searchController: UISearchController) {
        //对于由代码主动发起的searchController进入active状态,需在此设置        
        searchController.searchBar.becomeFirstResponder()
    }
}

3.UISearchResultsUpdating//根据searchResultsController是否为nil决定此代理由子MVC实现还是主MVC实现

//MARK: UISearchResultsUpdating
extension SearchResultsController: UISearchResultsUpdating {
    func updateSearchResultsForSearchController(searchController: UISearchController) {
        if self.searchController == nil {
            self.searchController = searchController
        }
        guard searchController.searchBar.text ?? "" != "" else {
            return
        }
        searchKeywords(searchController.searchBar.text!)
    }
}

示例项目传送门

最后附上示例项目传送门
https://github.com/LvJianting/UISearchControllerExample.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容