Как включить кнопку отмены с помощью UISearchBar? - PullRequest
50 голосов
/ 02 апреля 2012

В приложении контактов на iPhone, если вы вводите поисковый запрос, затем нажимаете кнопку «Поиск», клавиатура скрыта, НО кнопка отмены по-прежнему включена. В моем приложении кнопка отмены отключается, когда я вызываю resignFirstResponder.

Кто-нибудь знает, как спрятать клавиатуру, удерживая кнопку отмены во включенном состоянии?

Я использую следующий код:

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    [searchBar resignFirstResponder];
}

Клавиатура выдвигается из поля зрения, но кнопка «Отмена» справа от текстового поля поиска отключена, поэтому я не могу отменить поиск. Приложение контактов поддерживает кнопку отмены в активированном состоянии.

Я думаю, что, возможно, одним из решений является погружение в объект searchBar и вызов resignFirstResponder для фактического текстового поля, а не для самой панели поиска.

Любой вклад приветствуется.

Ответы [ 18 ]

29 голосов
/ 09 августа 2013

Этот метод работал в iOS7.

- (void)enableCancelButton:(UISearchBar *)searchBar
{
    for (UIView *view in searchBar.subviews)
    {
        for (id subview in view.subviews)
        {
            if ( [subview isKindOfClass:[UIButton class]] )
            {
                [subview setEnabled:YES];
                NSLog(@"enableCancelButton");
                return;
            }
        }
    }
}

(Обязательно вызывайте его где угодно после использования [_searchBar resignFirstResponder].)

21 голосов
/ 02 апреля 2012

попробуйте

for(id subview in [yourSearchBar subviews])
{
    if ([subview isKindOfClass:[UIButton class]]) {
        [subview setEnabled:YES];
    }
}
10 голосов
/ 13 сентября 2012

Принятое решение не будет работать, когда вы начнете прокручивать таблицу вместо нажатия кнопки «Поиск». В этом случае кнопка «Отмена» будет отключена.

Это мое решение, которое снова включает кнопку «Отмена» каждый раз, когда она отключается с помощью KVO.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // Search for Cancel button in searchbar, enable it and add key-value observer.
    for (id subview in [self.searchBar subviews]) {
        if ([subview isKindOfClass:[UIButton class]]) {
            [subview setEnabled:YES];
            [subview addObserver:self forKeyPath:@"enabled" options:NSKeyValueObservingOptionNew context:nil];
        }
    }
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    // Remove observer for the Cancel button in searchBar.
    for (id subview in [self.searchBar subviews]) {
        if ([subview isKindOfClass:[UIButton class]])
            [subview removeObserver:self forKeyPath:@"enabled"];
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    // Re-enable the Cancel button in searchBar.
    if ([object isKindOfClass:[UIButton class]] && [keyPath isEqualToString:@"enabled"]) {
        UIButton *button = object;
        if (!button.enabled)
            button.enabled = YES;
    }
}
9 голосов
/ 26 октября 2012

Начиная с iOS 6, кнопка выглядит как UINavigationButton (закрытый класс) вместо UIButton.

Я настроил приведенный выше пример, чтобы он выглядел следующим образом.

for (UIView *v in searchBar.subviews) {
    if ([v isKindOfClass:[UIControl class]]) {
        ((UIControl *)v).enabled = YES;
    }
}

Тем не менее, это очевидно хрупко, так как мы копаемся с внутренностями. Он также может активировать больше, чем кнопка, но он работает для меня, пока не будет найдено лучшее решение.

Мы должны попросить Apple раскрыть это.

8 голосов
/ 02 октября 2013

Мне показалось, что это работает (во viewDidLoad):

__unused UISearchDisplayController* searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];

Я понимаю, что, вероятно, мне следует правильно использовать UISearchDisplayController, но это было легко исправить для моей текущей реализации.

7 голосов
/ 13 июля 2015

Вы можете использовать API времени выполнения для доступа к кнопке отмены.

UIButton *btnCancel = [self.searchBar valueForKey:@"_cancelButton"];
[btnCancel setEnabled:YES];
5 голосов
/ 25 января 2013

Я расширил то, что другие здесь уже опубликовали, реализовав это как простую категорию на UISearchBar.

UISearchBar + alwaysEnableCancelButton.h

#import <UIKit/UIKit.h>

@interface UISearchBar (alwaysEnableCancelButton)

@end

UISearchBar + alwaysEnableCancelButton.m

#import "UISearchBar+alwaysEnableCancelButton.h"

@implementation UISearchBar (alwaysEnableCancelButton)

- (BOOL)resignFirstResponder
{
    for (UIView *v in self.subviews) {
        // Force the cancel button to stay enabled
        if ([v isKindOfClass:[UIControl class]]) {
            ((UIControl *)v).enabled = YES;
        }

        // Dismiss the keyboard
        if ([v isKindOfClass:[UITextField class]]) {
            [(UITextField *)v resignFirstResponder];
        }
    }

    return YES;
}
@end
4 голосов
/ 27 сентября 2013

Вот немного более надежное решение, которое работает на iOS 7. Он будет рекурсивно перебирать все подпредставления панели поиска, чтобы убедиться, что он включает все UIControl с (включая кнопку Отмена).

- (void)enableControlsInView:(UIView *)view
{
    for (id subview in view.subviews) {
        if ([subview isKindOfClass:[UIControl class]]) {
            [subview setEnabled:YES];
        }
        [self enableControlsInView:subview];
    }
}

Просто вызовите этот метод сразу после вызова [self.searchBar resignFirstResponder] следующим образом:

[self enableControlsInView:self.searchBar];

Вуаля! Кнопка отмены остается активной.

3 голосов
/ 04 марта 2014
for (UIView *firstView in searchBar.subviews) {
    for(UIView* view in firstView.subviews) {
        if([view isKindOfClass:[UIButton class]]) {
             UIButton* button = (UIButton*) view;
             [button setEnabled:YES];
        }
    }
}
2 голосов
/ 25 февраля 2014

Я нашел другой способ заставить его работать в iOS 7.

То, что я пытаюсь сделать, это что-то вроде приложения iOS для Twitter. Если щелкнуть увеличительное стекло на вкладке «Временные шкалы», появится UISearchBar с активированной кнопкой «Отмена», отображением клавиатуры и экраном недавних поисков. Прокрутите экран недавних поисков, и он скрывает клавиатуру, но при этом кнопка «Отмена» остается активной.

Это мой рабочий код:

UIView *searchBarSubview = self.searchBar.subviews[0];
NSArray *subviewCache = [searchBarSubview valueForKeyPath:@"subviewCache"];
if ([subviewCache[2] respondsToSelector:@selector(setEnabled:)]) {
    [subviewCache[2] setValue:@YES forKeyPath:@"enabled"];
}

Я пришел к этому решению, установив точку останова на моем табличном представлении scrollViewWillBeginDragging:. Я заглянул в свой UISearchBar и обнажил его подпредставления. Он всегда имеет только один тип UIView (моя переменная searchBarSubview).

enter image description here

Затем, что UIView содержит NSArray с именем subviewCache, и я заметил, что последний элемент, который является третьим, имеет тип UINavigationButton, а не в публичном API. Поэтому я решил использовать кодирование ключ-значение. Я проверил, отвечает ли UINavigationButton на setEnabled:, и, к счастью, это так. Поэтому я установил свойство на @YES. Оказывается, что UINavigationButton является кнопкой Отмена.

Это обязательно сломается, если Apple решит изменить реализацию внутренностей UISearchBar, но какого черта. Пока работает.

...