美文网首页iOS之家
UISearchController使用指南(Swift)

UISearchController使用指南(Swift)

作者: 暴走的ATM | 来源:发表于2016-07-03 20:52 被阅读900次

    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

    相关文章

      网友评论

      • Duskalbatross:这个问题困扰了我好几天,终于看到一篇全面、靠谱的文章做解释了,非常感谢!:smile:

      本文标题:UISearchController使用指南(Swift)

      本文链接:https://www.haomeiwen.com/subject/ixccjttx.html