iOS8无法隐藏UISearchController中搜索栏上的“取消”按钮

iOS8无法隐藏UISearchController中搜索栏上的“取消”按钮,ios,swift,ios8,uisearchbar,uisearchcontroller,Ios,Swift,Ios8,Uisearchbar,Uisearchcontroller,我的目标是防止“取消”按钮出现在UISearchController的搜索栏中。我开始使用并隐藏了取消按钮,如下面的代码剪报所示。但是,当用户点击文本字段时,取消按钮仍会出现。有什么帮助吗 override func viewDidLoad() { super.viewDidLoad() resultsTableController = ResultsTableController() searchController = UISearchController(sea

我的目标是防止“取消”按钮出现在UISearchController的搜索栏中。我开始使用并隐藏了取消按钮,如下面的代码剪报所示。但是,当用户点击文本字段时,取消按钮仍会出现。有什么帮助吗

override func viewDidLoad() {
    super.viewDidLoad()

    resultsTableController = ResultsTableController()

    searchController = UISearchController(searchResultsController: resultsTableController)
    searchController.searchResultsUpdater = self
    searchController.searchBar.sizeToFit()
    tableView.tableHeaderView = searchController.searchBar

    searchController.searchBar.delegate = self

    //Hide cancel button - added by me
    searchController.searchBar.showsCancelButton = false

    ...

我认为有三种方法可以实现这一目标:

  • 覆盖搜索显示控制器IDBEGINSEARCH,并使用以下代码:
  • searchController.searchBar.showsCancelButton=false

  • 子类UISearchBar并重写LayoutSubView,以便在系统尝试绘制该变量时更改该变量

  • 注册键盘通知UIKeyboardWillShowNotification并在1点应用代码。


  • 当然,您可以始终实现您的搜索栏。

    对于iOS 8和UISearchController,请从
    UISearchControllerDelegate
    使用此委托方法:

    func didPresentSearchController(searchController: UISearchController) {
      searchController.searchBar.showsCancelButton = false
    }
    

    不要忘记将自己设置为委托人:
    searchController.delegate=self

    以下github项目子类UISearchBar,作为解决方案2提供:

    最重要的是,它还对UISearchController进行了子类化,使人们能够将搜索栏放置在tableView标题以外的位置

    希望这有帮助。

    TL;博士: 子类化
    UISearchBar
    并覆盖
    setShowsCancelButton:
    setShowsCancelButton:animated:
    隐藏取消按钮

    解决方案 如果搜索栏不是第一个响应者(键盘未激活并显示),我将
    激活
    设置为
    ,因为这实际上是一个取消命令

    FJSearchBar 标记
    searchController.searchBar.showsCancelButton=NO
    在iOS 8中似乎不起作用。我还没有测试iOS 9

    FJSearchBar.h 空的,但为了完整性放在这里

    @import UIKit;
    
    @interface FJSearchBar : UISearchBar
    
    @end
    
    FJSearchBar.m FJSearchController 这里是你想要做出真正改变的地方。我将
    UISearchBarDelegate
    拆分为自己的类别,因为,依我看,这些类别使类更干净,更易于维护。如果您希望将委托保留在主类接口/实现中,那么非常欢迎您这样做

    FJSearchController.h 需要注意的一些部分:

  • 我将搜索栏和
    BOOL
    作为私有变量而不是属性,因为
    • 它们比私有财产更轻
    • 它们不需要被外界看到或修改
  • 我们检查
    搜索栏是否是第一响应者。如果不是,那么我们实际上会停用搜索控制器,因为文本是空的,我们不再搜索。如果您确实想确定,还可以确保
    searchText.length==0
  • searchBar:textDidChange:
    searchBar应该开始编辑:
    之前被调用,这就是我们按此顺序处理它的原因
  • 每次文本更改时,我都会更新搜索结果,但您可能希望移动
    [self.searchresultsUpdate-updateSearchResultsForSearchController:self]
    SearchBarSearchButton单击:
    如果您只希望在用户按下搜索按钮后执行搜索

  • 这是我在Swift中能想到的最简单的解决方案

    自定义搜索控制器:

    class CustomSearchController: UISearchController {
    
        var _searchBar: CustomSearchBar
    
        override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
            self._searchBar = CustomSearchBar()
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        }
    
        override init(searchResultsController: UIViewController?) {
            self._searchBar = CustomSearchBar()
            super.init(searchResultsController: searchResultsController)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override var searchBar: UISearchBar {
            return self._searchBar
        }
    }
    
    自定义搜索栏:

    class CustomSearchBar: UISearchBar {
        override func setShowsCancelButton(showsCancelButton: Bool, animated: Bool) {
            // do nothing
        }
    }
    

    最重要的一点是只在
    init
    中创建
    \u searchBar
    对象一次,而不是在存储属性中创建它。

    只需将
    UISearchController
    UISearchBar
    子类化即可

    class NoCancelButtonSearchController: UISearchController {
        let noCancelButtonSearchBar = NoCancelButtonSearchBar()
        override var searchBar: UISearchBar { return noCancelButtonSearchBar }
    }
    
    class NoCancelButtonSearchBar: UISearchBar {
        override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) { /* void */ }
    }
    

    使用UISearchControllerDelegate

    func willPresentSearchController(_ searchController: UISearchController) {
    
            searchController.searchBar.setValue("", forKey:"_cancelButtonText")
        }
    

    只需对UISearchController进行子类化,并执行以下操作:

    class CustomSearchController: UISearchController {
    
       override func viewDidLayoutSubviews() {
           super.viewDidLayoutSubviews()
           searchBar.showsCancelButton = false
       }
    }
    

    为了解决闪烁的取消按钮问题,这是我能想到的最简单的解决方案。

    Swift:

    在viewDidLoad下添加的以下内容对我很有用,因为我从来不想要那个按钮:

    let searchBarStyle = searchBar.value(forKey: "searchField") as? UITextField
    searchBarStyle?.clearButtonMode = .never
    
    确保在情节提要中添加搜索栏的ID。

    1:在iOS 8中不推荐使用。它是一个替换
    didPresentSearchController:
    在取消按钮显示后被调用,导致闪烁。2:我认为你不能告诉
    UISearchController
    使用搜索栏的自定义子类?3:如果没有显示键盘,情况会怎样?例如,如果键盘配对/连接?+1表示#1。我没有收到任何关于折旧的警告,我看不到闪烁,似乎工作正常,这是代码最少的解决方案。正如@jemmons指出的,这可以工作,但会导致闪烁,因为我们隐藏了“取消”按钮,当它已经存在时。@MichaelPirotte从iOS 9.3.1开始,它仍然闪烁。它在iOS 12上工作,但是有一点跳跃的动画(
    func willPresentSearchController(_ searchController: UISearchController) {
    
            searchController.searchBar.setValue("", forKey:"_cancelButtonText")
        }
    
    class CustomSearchController: UISearchController {
    
       override func viewDidLayoutSubviews() {
           super.viewDidLayoutSubviews()
           searchBar.showsCancelButton = false
       }
    }
    
    let searchBarStyle = searchBar.value(forKey: "searchField") as? UITextField
    searchBarStyle?.clearButtonMode = .never