Отключение клавиатуры от UISearchBar при нажатии кнопки X

Я использую UISearchBar (но не SearchDisplayController, который обычно используется в сочетании), и я хотел бы убрать клавиатуру, когда вы нажимаете кнопку "X".

Я следовал предложению TomSwift о вызове, когда "X" прослушивается, и это отлично работает. Но отставка первого ответчика из текстового поля, а также вызов в экземпляре UISearchBar, как с resignFirstResponder, не заставят клавиатуру уйти.

Есть ли способ избавиться от клавиатуры, когда пользователь нажал кнопку X?

Вот что я сделал, чтобы получить сообщение "Очистить":

- (void)viewDidLoad:
{
    for (UIView* v in searchBar.subviews)
    {
        if ( [v isKindOfClass: [UITextField class]] )
        {
            UITextField *tf = (UITextField *)v;
            tf.delegate = self;
            break;
        }
    }    
}

Затем у меня есть моя настройка класса для реализации как UISearchBarDelegate, так и UITextFieldDelegate.

Наличие класса в качестве делегата текстового поля позволяет мне получить этот вызов:

- (BOOL)textFieldShouldClear:(UITextField *)textField
{
     [textField resignFirstResponder];
     [self.searchBar resignFirstResponder];
     return YES;
}

Я пробовал все, что мог придумать. Последнее, что я пытаюсь найти способ вывести "searchBarCancelButtonClicked", который UISearchDelegate будет вызывать в моем классе Controller, но не уверен, как я мог это сделать, поскольку UISearchBar, похоже, не имеет прямых методов для вызывается с этим именем.

Ответ 1

Update:

Ну, это полный хак, но я смог заставить его работать. В основном код вызывает обработчик для кнопки отмены. Чтобы заставить его работать, мне пришлось вызывать селектор с задержкой, и я не уверен, почему это должно было быть. Кроме того, мне пришлось написать аксессуар для кнопки отмены, как и для текстового поля.

Опять же, это полный взлом. Я не уверен, что сделаю это сам в приложении.

// this in the context of the search bar
- (UIButton*) cancelButton
{
    for (UIView* v in self.subviews)
    {
        if ( [v isKindOfClass: [UIButton class]] )
            return (UIButton*)v;
    }

    return nil;
}

// this is the textField delegate callback
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
    [textField resignFirstResponder];

    UIButton* cb = _searchBar.cancelButton;

    NSObject* target = [[cb allTargets] anyObject];

    NSArray* actions = [cb actionsForTarget: target forControlEvent:UIControlEventTouchUpInside];

    NSString* selectorName = [actions  objectAtIndex:0];

    SEL selector = NSSelectorFromString( selectorName );

    [target performSelector: selector withObject: cb afterDelay: 0.1];

    return YES;
}

Оригинальный ответ:

Как вы получаете четкую кнопку "X" для отображения в первую очередь? В моем тестовом примере я не вижу его отображения...

Попробуйте выполнить resignFirstResponder в searchBar, а не в текстовом поле.

Ответ 2

Томс ответ заставил меня думать. Если это так, что панель поиска еще не является первымResponder, когда пользователь нажимает кнопку очистки, мы можем просто подождать, пока она не появится, а затем у вас будет resignFirstResponder; т.е. вдоль линий:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
  [self performFilteringBySearchText: searchText]; // or whatever

  // The user clicked the [X] button or otherwise cleared the text.
  if([searchText length] == 0) {
    [searchBar performSelector: @selector(resignFirstResponder) 
                    withObject: nil 
                    afterDelay: 0.1];
  }
}

Работает как шарм и менее хаки, чем Том ИМХО.

Ответ 3

Это работает:

[searchBar performSelector:@selector(resignFirstResponder) withObject:nil afterDelay:0.1];

Ответ 4

Обновлено для SWIFT 3:

Предположим, что пользователь ввел строку в поле поиска и щелкнул по x следующий код работает, чтобы скрыть клавиатуру при нажатии x

`

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) 
{
            if searchBar.text == nil || searchBar.text == ""
            {
                searchBar.perform(#selector(self.resignFirstResponder), with: nil, afterDelay: 0.1)
            }
 }

`

Ответ 5

Вы можете resignFirstResponder нажать кнопку отмены как.

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar

{

    SearchBar.showsCancelButton =NO;

}


- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{

    [SearchBar resignFirstResponder];


}

Ответ 6

Версия Swift 2:

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
        // The user clicked the [X] button or otherwise cleared the text.
        if (searchText.characters.count == 0) {
            searchBar.performSelector("resignFirstResponder", withObject: nil, afterDelay: 0.1)
        }
    }

Ответ 8

Старайтесь избегать

- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar

в вашем коде мы можем решить этот

Ответ 9

Я использовал комбинацию ответа @radiospiel, а также ответ, который @Tozar связан с:

@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

Ответ 10

Не следует ли изменять пользовательский интерфейс в основном потоке вместо использования performselector:WithObject:afterDelay:?

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if (searchText.length == 0) {
        [searchBar performSelectorOnMainThread:@selector(resignFirstResponder) withObject:nil waitUntilDone:NO];
    }
}

Ответ 11

РЕДАКТИРОВАТЬ: На самом деле ниже разбивается делегат, подключенный к UISearchBar. Просто подкласс UISearchBar и перезаписать метод UITextField Delegate.

===========================

Мне пришлось сделать это, чтобы получить доступ к UITextView

for (UIButton* v in [self.searchBar.subviews[0] subviews])
{
    if ( [v isKindOfClass: [UITextField class]] )
    {
        UITextField *tf = (UITextField *)v;
        tf.delegate = self;
        break;
    }
}

Ответ 12

Кредит Maxhs за оригинальный ответ: Это быстрая версия 2.2: Работайте как очарование для меня

if searchBar.text == "" {
                dispatch_async(dispatch_get_main_queue(), { 
                    self.searchBar.resignFirstResponder()
                })
            }

Ответ 13

Еще одна точка зрения для прозрачного потока текста (аналогичная @TomSwift, но более понятная для меня и менее сложная). Кроме того, мне нужно скрыть кнопку "Отмена" после выхода из панели поиска, реализовать прямой поиск (после каждого символа) и таблицу обложки перед тем, как пользователь выполнит поиск.

//self.searchHoverView can cover table view
//performSearchWithSearchBar: method for performing search

#pragma mark - UISearchBarDelegate

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
    [searchBar setShowsCancelButton:YES animated:YES];
    self.searchHoverView.hidden = NO;
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    if (searchText.length) {
        [self performSearchWithSearchBar:searchBar];
    } else {
        UIButton *button;
        for (UIView *subView in [searchBar subviews]) {
            for (UIView *view in [subView subviews]) {
                if ([view isKindOfClass:[UIButton class]]) {
                    button = (UIButton *)view;
                    break;
                }
            }
        }

        if (button) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [button sendActionsForControlEvents:UIControlEventTouchUpInside];
            });
        }
    }
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    self.searchBar.text = nil;

    [self.searchBar setShowsCancelButton:NO animated:YES];
    [self.searchBar resignFirstResponder];

    self.searchHoverView.hidden = YES;
}