我能否钩取UISearchBar的清除按钮?

37

我在我的界面中使用了UISearchBar并想要自定义搜索栏中输入文本后出现的小清除按钮(它是一个带有交叉符号的小灰色圆圈,出现在搜索栏右侧)的行为。

基本上,我想让它不仅清除搜索栏中的文本(这是默认实现),还要通过调用自己的方法来清除我的界面中的其他一些内容。

我在UISearchBar类或UISearchBarDelegate协议的文档中找不到任何有关此行为的信息 - 看起来似乎无法直接访问此行为。

唯一注意到的一件事是文档解释了委托方法:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText;

在清除按钮被点击后调用。

最初我在这个方法中编写了一些代码,检查搜索栏的文本属性,如果为空,则已被清除,并完成所有其他操作。

但是有两个问题:

首先,出于某种无法理解的原因,即使我告诉搜索栏在我的方法结束时resignFirstResponder,但某些地方还是会将其设置回becomeFirstResponder。真的很烦人...

其次,如果用户不使用清除按钮,而只是使用键盘上的删除按钮删除栏中的文本,那么这个方法就会触发,他们的搜索结果也会消失。 不好。

有任何建议或指针都将非常感谢!

谢谢!


是的,您可以通过以下方式访问清除按钮:https://dev59.com/TV4b5IYBdhLWcg3wchNL#60147293 - Kedar Sukerkar
查看这个链接获取 Swift 5 的相关信息:https://dev59.com/TV4b5IYBdhLWcg3wchNL#60147293 - Kedar Sukerkar
9个回答

18

找到了更好的解决方案 :)

- (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];   
}

谢谢好的技巧,我在下面添加了Swift 2版本的答案。 - ergunkocak
使用ADC时,使用dispatch_async(dispatch_get_main_queue(), ^{ [searchBar resignFirstResponder]; });而不是performSelector和使用额外的函数会更加简洁。 - Rivera

12

7

Swift版本处理清除按钮单击关闭键盘:

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.characters.count == 0 {
        performSelector("hideKeyboardWithSearchBar:", withObject:searchBar, afterDelay:0)
    }
}

func hideKeyboardWithSearchBar(bar:UISearchBar) {
    bar.resignFirstResponder()
}

7

我在我的应用程序中有这段代码。不同之处在于,我不支持“实时搜索”,而是当用户触摸键盘上的搜索按钮时开始搜索:

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
    if ([searchBar.text isEqualToString:@""]) {
        //Clear stuff here
    }
}

+1 我同意这个答案。如果文本被清空后为空,则说明已按下清除按钮。@Jasarien,你找到解决方案了吗? - fearmint
请使用以下代码 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText 进行搜索栏文本更改的操作,否则,如果您在清除时需要放弃第一响应者,则用户将永远无法选择该框,因为当他们开始时它将是空的。 - Marc

2
你可以尝试这个方法:
- (void)viewDidLoad
{
    [super viewDidLoad];
    for (UIView *view in searchBar.subviews){
        for (UITextField *tf in view.subviews) {
            if ([tf isKindOfClass: [UITextField class]]) {
                tf.delegate = self;
                break;
            }
        }
    }
}

- (BOOL)textFieldShouldClear:(UITextField *)textField {
     // your code
    return YES;
}

2
在iOS 9上使用Swift 2对我不起作用。崩溃并显示错误“_searchController]: unrecognized selector sent to instance”。 - Sunkas

1

由于这是首先出现的,而且据我所见问题并没有得到充分解决,我想发表我的解决方案。

1) 您需要获取搜索栏内textField的引用 2) 您需要在textField触发时捕获它的清除事件。

这很简单。以下是一种方法。

a) 确保将您的类设置为 ,因为您将使用搜索栏内textField的委托方法。 b) 还要将您的搜索栏连接到类中的Outlet。我只是称之为searchBar。 c) 从viewDidLoad开始,您需要获取搜索栏内的textField。我是这样做的。

UITextField *textField = [self.searchBar valueForKey:@"_searchField"];
if (textField) {
    textField.delegate = self;
    textField.tag = 1000;
}

注意,我给那个textField分配了一个标签,这样我就可以再次获取它,并将其设置为textField代理。您可以创建一个属性并将该textField分配给该属性以便稍后获取它,但是我使用了一个标签。
从这里开始,您只需要调用委托方法即可:
-(BOOL)textFieldShouldClear:(UITextField *)textField {
if (textField.tag == 1000) {
    // do something
    return YES;
}
return NO;

}

就这样。由于您引用了一个私有的valueForKey,我不能保证它不会给您带来麻烦。


1
非常感谢你,伙计。 - SampathKumar

1
我建议使用UITextField的rightViewrightViewMode方法来创建自己的清除按钮,并使用相同的图像。当然,我假设UISearchBar会让你访问其中的UITextField。我认为它会。
请注意iPhone OS参考库中的以下内容:

如果叠加视图重叠在清除按钮上,则清除按钮始终优先接收事件。默认情况下,右侧叠加视图确实会重叠在清除按钮上。

因此,您可能还需要禁用原始的清除按钮。


0

根据我的经验,最好的解决方案是将一个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];

}

0

在这里找不到一个解决方案,它不使用私有API或者不是升级证明的,以防苹果更改UISearchBar的视图结构。这是我编写的可行代码:

- (void)viewDidLoad {
    [super viewDidLoad];

    UITextField* textfield = [self findTextFieldInside:self.searchBar];
    [textfield setDelegate:self];
}

- (UITextField*)findTextFieldInside:(id)mainView {
    for (id view in [mainView subviews]) {
        if ([view isKindOfClass:[UITextField class]]) {
            return view;
        }

        id subview = [self findTextFieldInside:view];
        if (subview != nil) {
            return subview;
        }
    }

    return nil;
}

然后在你的类中实现UITextFieldDelegate协议并重写textFieldShouldClear:方法。

- (BOOL)textFieldShouldClear:(UITextField*)textField {
    // Put your code in here.
    return YES;
}

编辑:在iOS8中,为搜索栏的文本字段设置委托将导致崩溃。但是,看起来在iOS8上清除时会调用searchBar:textDidChange:方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接