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

时间:2014-11-05 23:41:22

标签: ios swift ios8 uisearchbar uisearchcontroller

我的目标是阻止取消按钮出现在UISearchController的搜索栏中。我从Apple's Table Search with UISearchController sample code开始并隐藏了取消按钮,如下面的代码片段所示。但是,当用户点击文本字段时,仍会显示取消按钮。有什么帮助吗?

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

    ...

9 个答案:

答案 0 :(得分:17)

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

  1. 覆盖 searchDisplayControllerDidBeginSearch 并使用以下代码:
  2.   

    searchController.searchBar.showsCancelButton = false

    1. 子类UISearchBar并覆盖layoutSubviews以在系统尝试绘制var时更改该变量。

    2. 注册键盘通知 UIKeyboardWillShowNotification 并将代码应用于 1。

    3. 当然可以随时实现您的搜索栏。

答案 1 :(得分:17)

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

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

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

答案 2 :(得分:12)

简单地继承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 */ }
}

答案 3 :(得分:3)

以下github项目子类UISearchBar,显示为解决方案2:

https://github.com/mechaman/CustomSearchControllerSwift

除此之外,它还是UISearchController的子类,使其能够将搜索栏放在tableView标题以外的位置!

希望这有帮助。

答案 4 :(得分:2)

这是我在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
    }
}

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

答案 5 :(得分:2)

只需将UISearchController子类化并执行以下操作:

class CustomSearchController: UISearchController {

   override func viewDidLayoutSubviews() {
       super.viewDidLayoutSubviews()
       searchBar.showsCancelButton = false
   }
}

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

答案 6 :(得分:1)

<强> TL; DR : 子类化UISearchBar并覆盖setShowsCancelButton:setShowsCancelButton:animated:会隐藏取消按钮。

如果搜索栏不是第一个响应者(键盘未处于活动状态并显示),我将active设置为NO,因为这实际上是取消命令。 / p>

FJSearchBar

标记searchController.searchBar.showsCancelButton = NO似乎不适用于 iOS 8 。我还没有测试 iOS 9

FJSearchBar.h

清空,但放在这里是为了完整。

@import UIKit;

@interface FJSearchBar : UISearchBar

@end

FJSearchBar.m

#import "FJSearchBar.h"

@implementation FJSearchBar

- (void)setShowsCancelButton:(BOOL)showsCancelButton {
    // do nothing
}

- (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
    // do nothing
}

@end

FJSearchController

这是您想要进行真正更改的地方。我将UISearchBarDelegate拆分为自己的类别,因为恕我直言,这些类别使类更清晰,更易于维护。如果您想将委托保留在主类接口/实现中,那么非常欢迎您这样做。

FJSearchController.h

@import UIKit;

@interface FJSearchController : UISearchController

@end

@interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate>

@end

FJSearchController.m

#import "FJSearchController.h"
#import "FJSearchBar.h"

@implementation FJSearchController {
@private
    FJSearchBar *_searchBar;
    BOOL _clearedOutside;
}

- (UISearchBar *)searchBar {
    if (_searchBar == nil) {
        // if you're not hiding the cancel button, simply uncomment the line below and delete the FJSearchBar alloc/init
        // _searchBar = [[UISearchBar alloc] init];
        _searchBar = [[FJSearchBar alloc] init];
        _searchBar.delegate = self;
    }
    return _searchBar;
}

@end

@implementation FJSearchController (UISearchBarDelegate)

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
    // if we cleared from outside then we should not allow any new editing
    BOOL shouldAllowEditing = !_clearedOutside;
    _clearedOutside = NO;
    return shouldAllowEditing;
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    // hide the keyboard since the user will no longer add any more input
    [searchBar resignFirstResponder];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    if (![searchBar isFirstResponder]) {
        // the user cleared the search while not in typing mode, so we should deactivate searching
        self.active = NO;
        _clearedOutside = YES;
        return;
    }
    // update the search results
    [self.searchResultsUpdater updateSearchResultsForSearchController:self];
}

@end

需要注意的一些部分:

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

答案 7 :(得分:0)

使用UISearchControllerDelegate。

pod

答案 8 :(得分:0)

<强>夫特:

以下为我工作,在viewDidLoad下添加,因为我从来不想要那个按钮:

let searchBarStyle = searchBar.value(forKey: "searchField") as? UITextField
searchBarStyle?.clearButtonMode = .never

确保在故事板中添加searchBar的ID。 enter image description here