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

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

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

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

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

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

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

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

Ответы [ 18 ]

2 голосов
/ 03 декабря 2017

Большинство опубликованных решений не являются надежными и позволят отключить кнопку «Отмена» при различных обстоятельствах.

Я попытался внедрить решение, которое всегда сохраняет кнопку «Отмена» включенной, даже при выполнении более сложных задач.вещи с панелью поиска.Это реализовано в виде пользовательского подкласса UISearchView в Swift 4. Он использует трюк значения (forKey :), чтобы найти и кнопку отмены, и текстовое поле поиска, и прослушивает, когда поле поиска заканчивает редактирование, и снова включает кнопку отмены.Он также включает кнопку отмены при переключении флага showsCancelButton.

Он содержит пару утверждений, чтобы предупредить вас, если внутренние детали UISearchBar когда-либо изменятся, и не даст ему работать.

import UIKit

final class CancelSearchBar: UISearchBar {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }

    private func setup() {
        guard let searchField = value(forKey: "_searchField") as? UIControl else {
            assertionFailure("UISearchBar internal implementation has changed, this code needs updating")
            return
        }

        searchField.addTarget(self, action: #selector(enableSearchButton), for: .editingDidEnd)
    }

    override var showsCancelButton: Bool {
        didSet { enableSearchButton() }
    }

    @objc private func enableSearchButton() {
        guard showsCancelButton else { return }
        guard let cancelButton = value(forKey: "_cancelButton") as? UIControl else {
            assertionFailure("UISearchBar internal implementation has changed, this code needs updating")
            return
        }

        cancelButton.isEnabled = true
    }
}
2 голосов
/ 05 ноября 2015

SWIFT-версия для ответа Дэвида Дугласа (проверено на iOS9)

func enableSearchCancelButton(searchBar: UISearchBar){
    for view in searchBar.subviews {
        for subview in view.subviews {
            if let button = subview as? UIButton {
                button.enabled = true
            }
        }
    }
}
1 голос
/ 05 сентября 2014

Опираясь на ответ смайлиборга , просто поместите его в свой делегат searchBar:

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{   
    dispatch_async(dispatch_get_main_queue(), ^{
        __block __weak void (^weakEnsureCancelButtonRemainsEnabled)(UIView *);
        void (^ensureCancelButtonRemainsEnabled)(UIView *);
        weakEnsureCancelButtonRemainsEnabled = ensureCancelButtonRemainsEnabled = ^(UIView *view) {
            for (UIView *subview in view.subviews) {
                if ([subview isKindOfClass:[UIControl class]]) {
                [(UIControl *)subview setEnabled:YES];
                }
                weakEnsureCancelButtonRemainsEnabled(subview);
            }
        };

        ensureCancelButtonRemainsEnabled(searchBar);
    });
 }

Это решение хорошо работает на iOS 7 и выше.

1 голос
/ 05 июля 2017

Для iOS 9/10 (протестировано), Swift 3 (короче):

searchBar.subviews.flatMap({$0.subviews}).forEach({ ($0 as? UIButton)?.isEnabled = true })
1 голос
/ 09 января 2017

Для iOS 10, Swift 3:

for subView in self.movieSearchBar.subviews {
    for view in subView.subviews {
        if view.isKind(of:NSClassFromString("UIButton")!) {
            let cancelButton = view as! UIButton
            cancelButton.isEnabled = true
        }
    }
}
0 голосов
/ 22 июня 2017

Лучший и легкий метод:

[(UIButton *)[self.searchBar valueForKey:@"_cancelButton"] setEnabled:YES];
0 голосов
/ 20 октября 2016

Лучшее решение -

[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil].enabled = YES;
0 голосов
/ 03 марта 2015

Вы можете создать свой CustomSearchBar, наследующий от UISearchBar, и реализовать этот метод:

- (void)layoutSubviews {

    [super layoutSubviews];

    @try {
        UIView *baseView = self.subviews[0];

        for (UIView *possibleButton in baseView.subviews)
        {
            if ([possibleButton respondsToSelector:@selector(setEnabled:)]) {
                [(UIControl *)possibleButton setEnabled:YES];
            }
        }
    }
    @catch (NSException *exception) {
        NSLog(@"ERROR%@",exception);
    }
}
...