UISearchController 禁用取消 UIBarButtonItem
Posted
技术标签:
【中文标题】UISearchController 禁用取消 UIBarButtonItem【英文标题】:UISearchController disable cancel UIBarButtonItem 【发布时间】:2015-02-08 16:19:59 【问题描述】:问题
我正在尝试使用 UISearchController 在地图视图上搜索目的地。我希望 UISearchBar 出现在导航栏中,但如果它不显示右侧的取消按钮,我似乎无法这样做:
这个取消按钮有时会消失,而我正在玩,但我不能让它不出现现在我有搜索表显示我想要它的方式:
我敢肯定我做错了什么小事,但我无法弄清楚它是什么......
我的代码
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;
【问题讨论】:
嘿,我无法回答您的问题,但目前我正在尝试获得与您刚才所做的相同的功能。我想知道如何在没有 uitableView 的情况下使用 UiSearchBar 像您一样为地址创建建议列表。能否再提供一些代码示例? 【参考方案1】:有一种更简单的方法...
对于 ios 8 和 UISearchController,请使用来自 UISearchControllerDelegate
的此委托方法:
func didPresentSearchController(searchController: UISearchController)
searchController.searchBar.showsCancelButton = false
别忘了将自己设置为代表:searchController.delegate = self
【讨论】:
这种工作,但取消按钮短暂显示后消失。 @sdsykes 有趣...什么版本的 iOS?它根本不显示给我:( 我发现,按照上面的建议,随后对 showsCancelButton 的调用按预期工作,至少在我的情况下。【参考方案2】:根据 cmets 更新
UISearchBar
有一个属性(参见Apple docs)确定是否显示取消按钮:
self.searchBar.showsCancelButton = false;
但是,根据 OP cmets,这不起作用,因为 searchController 不断将取消按钮重新打开。为避免这种情况,请创建 UISearchBar 的子类,并覆盖 setShowsCancelButton
方法:
@implementation MySearchBar
-(void)setShowsCancelButton:(BOOL)showsCancelButton
// Do nothing...
-(void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated
// Do nothing....
@end
为了确保这个子类被 searchController 使用,我们还需要继承 UISearchController
,并重写 searchBar
方法以返回我们子类的实例。我们还需要确保新的 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
最后,改变你的代码来实例化这个子类:
self.searchController = [[MySearchController alloc] initWithSearchResultsController:self.resultsViewController];
(您显然需要为这些子类导入相关的头文件)。
【讨论】:
不幸的是不起作用,我相信这与搜索栏本身的取消按钮有关。这个搜索按钮似乎是由 UISearchController 控制的 @simonthumper 我已经用涉及子类化 searchBar 的解决方案更新了我的答案。 谢谢,这是我正在考虑的,但希望有一个更简单的解决方案。我今晚可能会有机会实施,然后我会标记为正确:) updateSearchResultsForSearchController 在我使用此方法时停止工作。有什么建议吗? @vinnybad 抱歉,在我实现 textDidChange 方法来激活搜索控制器之前,我遇到了这个问题。但这为我解决了问题。【参考方案3】: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
在 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
)()
而且它工作正常且流畅
【讨论】:
完美运行,也适用于 Swift 4.2 和 iOS 11/12。【参考方案4】:你可以这样做:
- (void)willPresentSearchController:(UISearchController *)searchController
dispatch_async(dispatch_get_main_queue(), ^
searchController.searchBar.showsCancelButton = NO;
);
【讨论】:
【参考方案5】:@pbasdf 的答案在大多数情况下都有效,但检查searchText
长度以确定UISearchController
是否处于活动状态可以为用户增加更多工作。极端情况是用户点击 clear 按钮,或删除搜索栏中的唯一字符。这会将active
设置为NO
,这将自动在UISearchBar
上调用resignFirstResponder
。键盘会消失,如果用户想要更改文本或输入更多文本,则需要再次点击搜索栏。
相反,如果搜索栏不是第一响应者(键盘未激活和显示),我只将 active
设置为 NO
,因为这实际上是一个 cancel 命令。 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
一些需要注意的部分:
-
我已将搜索栏和
BOOL
作为私有变量而不是属性,因为
它们比私有属性更轻量级。
它们不需要被外界看到或修改。
我们检查searchBar
是否是第一响应者。如果不是,那么我们实际上停用了搜索控制器,因为文本为空并且我们不再搜索。如果你真的想确定,你也可以确定searchText.length == 0
。
searchBar:textDidChange:
在 searchBarShouldBeginEditing:
之前调用,这就是我们按此顺序处理它的原因。
我会在每次文本更改时更新搜索结果,但如果您只想在用户按下 搜索 按钮后执行搜索,则可能需要将 [self.searchResultsUpdater updateSearchResultsForSearchController:self];
移动到 searchBarSearchButtonClicked:
。
【讨论】:
【参考方案6】:通过在几个UISearchBarDelegate
方法中调用setShowsCancelButton
,我能够使UISearchBar
的行为符合预期,而无需子类化:
我称之为textDidChange
和searchBarCancelButtonClicked
。这是我的实现的样子:
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
【讨论】:
以上是关于UISearchController 禁用取消 UIBarButtonItem的主要内容,如果未能解决你的问题,请参考以下文章
iOS UISearchController:等到 UISearchController 在取消搜索后被解除
按下取消按钮时如何防止 UISearchController 关闭?