[英]UISearchController disable cancel UIBarButtonItem
I am trying to use UISearchController to search for a destination on a map view. 我试图使用UISearchController在地图视图上搜索目的地。 I want the UISearchBar to appear in the navigation bar, but I can't seem to make it do so without it showing a cancel button to the right of it:
我希望UISearchBar出现在导航栏中,但我似乎无法在没有显示右侧的取消按钮的情况下这样做:
This Cancel button has disappeared at times, whilst I'm playing around, but I can't get it to not appear now I have got the search table showing how I want it to: 这个取消按钮有时会消失,而我正在玩耍,但我现在无法让它显示我的搜索表显示我想要它:
I'm sure there must be something small I'm doing ever so slightly wrong, but I can't work out what it is... 我肯定必须有一些我做得有点小错误的东西,但我无法弄清楚它是什么......
self.resultsViewController = [UITableViewController new];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsViewController];
self.searchController.searchResultsUpdater = self;
self.searchController.hidesNavigationBarDuringPresentation = false;
self.searchController.delegate = self;
self.searchBar = self.searchController.searchBar;
self.searchBar.placeholder = self.stage.title;
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.definesPresentationContext = true;
self.navigationItem.titleView = self.searchBar;
self.resultsTableView = self.resultsViewController.tableView;
self.resultsTableView.dataSource = self;
self.resultsTableView.delegate = self;
There is a way easier way... 有一种更简单的方法......
For iOS 8, and UISearchController, use this delegate method from UISearchControllerDelegate
: 对于iOS 8,和UISearchController,使用该委托方法从
UISearchControllerDelegate
:
func didPresentSearchController(searchController: UISearchController) {
searchController.searchBar.showsCancelButton = false
}
Don't forget to set yourself as the delegate: searchController.delegate = self
不要忘记将自己设置为委托:
searchController.delegate = self
Updated in light of comments 根据评论更新
UISearchBar
has a property (see the Apple docs ) which determines whether the cancel button is displayed: UISearchBar
有一个属性(参见Apple文档 ),它确定是否显示取消按钮:
self.searchBar.showsCancelButton = false;
But, as per OP comments, this does not work, because the searchController keeps switching the cancel button back on. 但是,根据OP注释,这不起作用,因为searchController不断重新打开取消按钮。 To avoid this, create a subclass of UISearchBar, and override the
setShowsCancelButton
methods: 要避免这种情况,请创建UISearchBar的子类,并覆盖
setShowsCancelButton
方法:
@implementation MySearchBar
-(void)setShowsCancelButton:(BOOL)showsCancelButton {
// Do nothing...
}
-(void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
// Do nothing....
}
@end
To ensure this subclass is used by the searchController, we also need to subclass UISearchController
, and override the searchBar
method to return an instance of our subclass. 为确保searchController使用此子类,我们还需要子类化
UISearchController
,并覆盖searchBar
方法以返回子类的实例。 We also need to ensure that the new searchBar activates the searchController - I've chosen to use the UISearchBarDelegate
method textDidChange
for this: 我们还需要确保新的searchBar激活searchController - 我选择使用
UISearchBarDelegate
方法textDidChange
:
@interface MySearchController () <UISearchBarDelegate> {
UISearchBar *_searchBar;
}
@end
@implementation MySearchController
-(UISearchBar *)searchBar {
if (_searchBar == nil) {
_searchBar = [[MySearchBar alloc] initWithFrame:CGRectZero];
_searchBar.delegate = self;
}
return _searchBar;
}
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if ([searchBar.text length] > 0) {
self.active = true;
} else {
self.active = false;
}
}
@end
Finally, change your code to instantiate this subclass: 最后,更改代码以实例化此子类:
self.searchController = [[MySearchController alloc] initWithSearchResultsController:self.resultsViewController];
(You will obviously need to import the relevant header files for these subclasses). (您显然需要导入这些子类的相关头文件)。
Easy solution in Swift3 - we need to make CustomSearchBar without cancel button and then override the corresponding property in new CustomSearchController : Swift3中的简单解决方案 - 我们需要使用CustomSearchBar而不使用取消按钮,然后覆盖新CustomSearchController中的相应属性:
class CustomSearchBar: UISearchBar {
override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) {
super.setShowsCancelButton(false, animated: false)
}}
class CustomSearchController: UISearchController {
lazy var _searchBar: CustomSearchBar = {
[unowned self] in
let customSearchBar = CustomSearchBar(frame: CGRect.zero)
return customSearchBar
}()
override var searchBar: UISearchBar {
get {
return _searchBar
}
}}
In MyViewController I initialize and configure searchController using this new custom subclass: 在MyViewController中,我使用这个新的自定义子类初始化和配置searchController:
var videoSearchController: UISearchController = ({
// Display search results in a separate view controller
// let storyBoard = UIStoryboard(name: "Main", bundle: Bundle.main)
// let alternateController = storyBoard.instantiateViewController(withIdentifier: "aTV") as! AlternateTableViewController
// let controller = UISearchController(searchResultsController: alternateController)
let controller = CustomSearchController(searchResultsController: nil)
controller.searchBar.placeholder = NSLocalizedString("Enter keyword (e.g. iceland)", comment: "")
controller.hidesNavigationBarDuringPresentation = false
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.searchBarStyle = .minimal
controller.searchBar.sizeToFit()
return controller
})()
And it works properly and smooth 它运作正常,顺畅
You could do like this: 你可以这样做:
- (void)willPresentSearchController:(UISearchController *)searchController {
dispatch_async(dispatch_get_main_queue(), ^{
searchController.searchBar.showsCancelButton = NO;
}); }
@pbasdf 's answer works for the most part, but checking the searchText
length to determine whether the UISearchController
is active can add more work to the user. @pbasdf的答案大部分都有用 ,但检查
searchText
长度以确定UISearchController
是否处于活动状态可以为用户添加更多工作。 The corner case would be if the user hits the clear button, or deletes the only character in the search bar. 如果用户点击清除按钮,或者删除搜索栏中的唯一字符,则会出现转角情况。 This would set
active
to NO
, which would automatically call resignFirstResponder
on the UISearchBar
. 这会将
active
设置为NO
,这将自动调用UISearchBar
上的resignFirstResponder
。 The keyboard would disappear and if the user wants to change the text or enter more text, it would require tapping again on the search bar. 键盘将消失,如果用户想要更改文本或输入更多文本,则需要在搜索栏上再次点击。
Instead, I only set active
to NO
if the search bar is not the first responder (keyboard is not active and displayed), since that is effectively a cancel command. 相反,如果搜索栏不是第一个响应者(键盘未激活并显示),我只将
active
设置为NO
,因为这实际上是取消命令。
Marking searchController.searchBar.showsCancelButton = NO
doesn't seem to work in iOS 8 . 标记
searchController.searchBar.showsCancelButton = NO
似乎在iOS 8中不起作用。 I haven't tested iOS 9 . 我还没有测试iOS 9 。
Empty, but placed here for completeness. 空,但放在这里是为了完整。
@import UIKit;
@interface FJSearchBar : UISearchBar
@end
#import "FJSearchBar.h"
@implementation FJSearchBar
- (void)setShowsCancelButton:(BOOL)showsCancelButton {
// do nothing
}
- (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
// do nothing
}
@end
Here's where you want to make the real changes. 这是你想要做出真正改变的地方。 I split the
UISearchBarDelegate
into its own category because, IMHO, the categories make the classes cleaner and easier to maintain. 我将
UISearchBarDelegate
拆分为自己的类别,因为恕我直言,这些类使类更清晰,更易于维护。 If you want to keep the delegate within the main class interface/implementation, you're more than welcome to do so. 如果您希望将委托保留在主类接口/实现中,那么非常欢迎您这样做。
@import UIKit;
@interface FJSearchController : UISearchController
@end
@interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate>
@end
#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
Some parts to note: 需要注意的部分内容:
BOOL
as private variables instead of properties because BOOL
作为私有变量而不是属性,因为
searchBar
is the first responder. searchBar
是否是第一个响应者。 If it's not, then we actually deactivate the search controller because the text is empty and we're no longer searching. searchText.length == 0
. searchText.length == 0
。 searchBar:textDidChange:
is invoked before searchBarShouldBeginEditing:
, which is why we handled it in this order. searchBar:textDidChange:
在searchBarShouldBeginEditing:
之前调用,这就是我们按此顺序处理它的原因。 [self.searchResultsUpdater updateSearchResultsForSearchController:self];
[self.searchResultsUpdater updateSearchResultsForSearchController:self];
to searchBarSearchButtonClicked:
if you only want the search performed after the user presses the Search button. searchBarSearchButtonClicked:
如果您只想在用户按下“ 搜索”按钮后执行搜索 。 I was able to get the UISearchBar
to behave as desired without subclassing by calling setShowsCancelButton
in a couple of UISearchBarDelegate
methods: 通过在几个
UISearchBarDelegate
方法中调用setShowsCancelButton
,我能够通过调用setShowsCancelButton
来使UISearchBar
无需子类化即可按行为运行:
I call it in textDidChange
and searchBarCancelButtonClicked
. 我在
textDidChange
和searchBarCancelButtonClicked
调用它。 Here's what my implementation looks like: 这是我的实现的样子:
extension MyViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.characters.isEmpty == false {
searchBar.setShowsCancelButton(true, animated: true)
// whatever extra stuff you need to do
} else {
searchBar.setShowsCancelButton(false, animated: true)
// whatever extra stuff you need to do
}
// whatever extra stuff you need to do
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: false)
searchBar.text = nil
searchBar.resignFirstResponder()
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
// whatever extra stuff you need to do
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.