UISearchbar clearButton强制显示键盘

我有一个UISearchBar作为一个表视图的生活filter。 当通过endEditing:键盘被解除时,查询文本和灰色圆形“清除”button保持不变。 从这里,如果我点击灰色的“清除”button,键盘会在文本被清除时重新出现。

我如何防止这种情况? 如果键盘当前没有打开,我希望该button清除文本,而无需重新打开键盘。

有一个协议方法,当我点击清除button时被调用。 但发送UISearchBar resignFirstResponder消息不会对键盘有任何影响。

这是一个古老的问题,我刚刚遇到同样的问题,并设法解决它的方式如下:

当由于用户点击“清除”button而调用UISearchBarDelegate的searchBar:textDidChange:方法时,searchBar还没有成为第一响应者,所以我们可以利用这一点来检测用户实际上何时旨在清除search,而不是把焦点放到search条上和/或做别的事情。

为了跟踪这一点,我们需要在我们的viewController中声明一个BOOL ivar,它也是searchBar委托(让我们把它shouldBeginEditing ),并将其初始值设置为YES (假设我们的viewController类被称为SearchViewController):

 @interface SearchViewController : UIViewController <UISearchBarDelegate> { // all of our ivar declarations go here... BOOL shouldBeginEditing; .... } ... @end @implementation SearchViewController ... - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { ... shouldBeginEditing = YES; } } ... @end 

稍后,在UISearchBarDelegate中,我们实现了searchBar:textDidChange:searchBarShouldBeginEditing:方法:

 - (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText { NSLog(@"searchBar:textDidChange: isFirstResponder: %i", [self.searchBar isFirstResponder]); if(![searchBar isFirstResponder]) { // user tapped the 'clear' button shouldBeginEditing = NO; // do whatever I want to happen when the user clears the search... } } - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)bar { // reset the shouldBeginEditing BOOL ivar to YES, but first take its value and use it to return it from the method call BOOL boolToReturn = shouldBeginEditing; shouldBeginEditing = YES; return boolToReturn; } 

基本上就是这样。

最好

我发现resignFirstResponder不起作用,当从触摸调用textDidChange到“清除button”。 但是,使用performSelection: withObject: afterDelay:似乎是一个有效的解决方法:

 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { if ([searchText length] == 0) { [self performSelector:@selector(hideKeyboardWithSearchBar:) withObject:searchBar afterDelay:0]; } } - (void)hideKeyboardWithSearchBar:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; } 

我发现了一个非常安全的方法来知道清除button是否被按下,并忽略用户刚删除UISearchBar的最后一个字符的时间。 这里是 :

 - (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { _isRemovingTextWithBackspace = ([searchBar.text stringByReplacingCharactersInRange:range withString:text].length == 0); return YES; } - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { if (searchText.length == 0 && !_isRemovingTextWithBackspace) { NSLog(@"Has clicked on clear !"); } } 

非常简单明了,是不是:)? 唯一需要注意的是,如果用户在编辑UISearchBar的UITextField时单击清除button,将会有两个ping,而如果用户在未编辑时单击它,则只会获得一个ping。


编辑:我不能testing它,但这是迅捷的版本,按照Rotem:

 var isRemovingTextWithBackspace = false func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { self.isRemovingTextWithBackspace = (NSString(string: searchBar.text!).stringByReplacingCharactersInRange(range, withString: text).characters.count == 0) return true } func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { if searchText.characters.count == 0 && !isRemovingTextWithBackspace { NSLog("Has clicked on clear !") } } 

@ Rotem的更新(Swift2):

 var isRemovingTextWithBackspace = false func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { self.isRemovingTextWithBackspace = (NSString(string: searchBar.text!).stringByReplacingCharactersInRange(range, withString: text).characters.count == 0) return true } func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { if searchText.characters.count == 0 && !isRemovingTextWithBackspace { NSLog("Has clicked on clear!") } } 

我使用@ boliva的答案和@ radiospiel的答案结合了一个不同的SO问题:

 @interface SearchViewController : UIViewController <UISearchBarDelegate> { // all of our ivar declarations go here... BOOL shouldBeginEditing; .... } ... @end @implementation SearchViewController ... - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { ... shouldBeginEditing = YES; } } ... - (void) searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText { // TODO - dynamically update the search results here, if we choose to do that. if (![searchBar isFirstResponder]) { // The user clicked the [X] button while the keyboard was hidden shouldBeginEditing = NO; } else if ([searchText length] == 0) { // The user clicked the [X] button or otherwise cleared the text. [theSearchBar performSelector: @selector(resignFirstResponder) withObject: nil afterDelay: 0.1]; } } - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)bar { // reset the shouldBeginEditing BOOL ivar to YES, but first take its value and use it to return it from the method call BOOL boolToReturn = shouldBeginEditing; shouldBeginEditing = YES; return boolToReturn; } @end 

从我的经验来看,最好的解决办法就是在系统清除button的上方放一个UIButton (背景清晰,没有文字),然后连接一个IBAction

自动布局只是简单的

 - (IBAction)searchCancelButtonPressed:(id)sender { [self.searchBar resignFirstResponder]; self.searchBar.text = @""; // some of my stuff self.model.fastSearchText = nil; [self.model fetchData]; [self reloadTableViewAnimated:NO]; } 

在你的endEditing方法中,你为什么不清除UISearchBar呢? 因为那也一定是你辞职的第一反应者,这是有道理的。

在search栏中,委托调用要求您接受从旧值到新值的更改 – 您可以检测到新值为零,旧值不为零,并且指示用户没有input任何东西,因为键盘是最后一次 – 然后在这种情况下,退出search栏的第一响应者。 不知道键盘是否会暂时显示。

我有一个非常相似的情况,可能会尝试自己。

触摸清除button会导致searchText为空。 另一种实现方法是检查- (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText空文本- (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText

 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { if([searchText length] == 0) { [self dismissSearch]; } else { self.searchResultsTable.hidden = YES; [self handleSearchForString:searchText]; } } - (void)dismissSearch { [self.searchBar performSelector: @selector(resignFirstResponder) withObject: nil afterDelay: 0.1]; self.searchResultsTable.hidden = YES; } 

对于那些在iOS 8或更高版本中使用UISearchController ,你只需要简单地UISearchController 。 为了完整起见,您也可以像我一样隐藏取消button,因为清除UISearchBar的文本实际上是取消search。 如果你想使用它,我已经添加了下面的代码。

这样做的好处是你可以将它用于任何类和任何视图,而不需要UIViewController的子类。 我甚至将包括如何初始化我的UISearchController在这个解决scheme的底部。

FJSearchBar

如果您想像我一样隐藏取消button,只需重写此类。 标记searchController.searchBar.showsCancelButton = NO似乎不适用于iOS 8 。 我还没有testingiOS 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. 我已经把search栏和BOOL作为私有variables,而不是属性,因为
    • 他们比私有财产更轻量。
    • 他们不需要被外界看到或修改。
  2. 我们检查searchBar是否是第一个响应者。 如果不是,那么我们实际上停用search控制器,因为文本是空的,我们不再search。 如果你真的想确定,你也可以确保searchText.length == 0
  3. searchBar:textDidChange:searchBarShouldBeginEditing:之前被调用,这就是为什么我们按这个顺序处理它的原因。
  4. 我每次更新文本都会更新search结果,但是您可能需要移动[self.searchResultsUpdater updateSearchResultsForSearchController:self]; searchBarSearchButtonClicked:如果您只想在用户按下searchbutton后执行search

我已经碰到过好几次了 我很欣赏人们给出的答案。

最终,我真的希望看到苹果允许我们(开发人员)检测何时按下了清除button。

很明显,按下它会被检测到,因为search框中的任何文本都被清除。

我猜测它现在的优先级并不是很高。但是我真的希望苹果的一个人给UISearchBar一点爱心!