Подтвердить что ты не робот

UISearchBar отключить автоматическое отключение кнопки отмены

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

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

Когда я посмотрел в заголовочном файле UISearchBar, я заметил флаг для autoDisableCancelButton в структуре _searchBarFlags, но он закрыт.

Есть ли что-то, что мне не хватает при настройке UISearchBar?

4b9b3361

Ответ 1

Я нашел решение. Вы можете использовать этот цикл for для петли над подзонами панели поиска и включать ее, когда кнопка поиска нажата на клавиатуре.

for (UIView *possibleButton in searchBar.subviews)
{
    if ([possibleButton isKindOfClass:[UIButton class]])
    {
        UIButton *cancelButton = (UIButton*)possibleButton;
        cancelButton.enabled = YES;
        break;
    }
}

Ответ 2

Мне пришлось немного подкорректировать это, чтобы заставить его работать для меня в 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;
            }
        }
    }
}

Ответ 3

Есть два способа добиться этого легко

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
    //  The small and dirty
    [(UIButton*)[searchBar valueForKey:@"_cancelButton"] setEnabled:YES];

    // The long and safe
     UIButton *cancelButton = [searchBar valueForKey:@"_cancelButton"];
    if ([cancelButton respondsToSelector:@selector(setEnabled:)]) {
         cancelButton.enabled = YES;
    }
}

Вы должны пойти со вторым, это не приведет к сбою вашего приложения, если Apple изменит его в фоновом режиме.

BTW я тестировал его с iOS 4.0 до 8.2 и никаких изменений, также я использую его в приложении, одобренном в Магазине, без каких-либо проблем.

Ответ 4

Именно это заставило меня работать на iOS 6 для меня:

searchBar.showsCancelButton = YES;
searchBar.showsScopeBar = YES;
[searchBar sizeToFit];
[searchBar setShowsCancelButton:YES animated:YES];

Ответ 5

Здесь мое решение, которое работает для всех ситуаций во всех версиях iOS.

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

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

// This will handle whenever the text field is resigned non-programatically
// (IE, because it set to resign when the scroll view is dragged in your storyboard.)
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
    [self performSelector:@selector(enableCancelButton:) withObject:searchBar afterDelay:0.001];
}

// Also follow up every [searchBar resignFirstResponder];
// with [self enableCancelButton:searchBar];

Ответ 6

Ни один из ответов не работал у меня вообще. Я нацелен на iOS 7. Но я нашел ответ.

То, что я пытаюсь, похоже на приложение Twitter iOS. Если вы нажмете на увеличительное стекло на вкладке Timelines, появится 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 внутренних, но какого черта. Он работает сейчас.

Ответ 7

В соответствии с моим ответом здесь, поместите это в свой делегат 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);
    });
}

Ответ 8

Для Monotouch или Xamarin iOS у меня есть следующее решение С#, работающее для iOS 7 и iOS 8:

foreach(UIView view in searchBar.Subviews)
{
    foreach(var subview in view.Subviews)
    {
        //Console.WriteLine(subview.GetType());
        if(subview.GetType() == typeof(UIButton))
        {
            if(subview.RespondsToSelector(new Selector("setEnabled:")))
            {
                UIButton cancelButton = (UIButton)subview;
                cancelButton.Enabled = true;
                Console.WriteLine("enabledCancelButton");
                return;
            }
        }
    }
}

Этот ответ основан на решении Дэвида Дугласа.

Ответ 9

Более полный ответ:

  • так как iOS 7, есть дополнительный уровень подзадач в поискеBar
  • Хорошее место для включения кнопки отмены находится в searchBarTextDidEndEditing

.

extension MyController: UISearchBarDelegate {
  public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    DispatchQueue.main.async {
    // you need that since the disabling will
    // happen after searchBarTextDidEndEditing is called
      searchBar.subviews.forEach({ view in
        view.subviews.forEach({ subview in
          // ios 7+
          if let cancelButton = subview as? UIButton {
            cancelButton.isEnabled = true
            cancelButton.isUserInteractionEnabled = true
            return
          }
        })
        // ios 7-
        if let cancelButton = subview as? UIButton {
          cancelButton.isEnabled = true
          cancelButton.isUserInteractionEnabled = true
          return
        }
      })
    }
  }
}

Ответ 10

Здесь быстрое решение, которое использует расширения, чтобы легко получить кнопку отмены:

extension UISearchBar {
    var cancelButton: UIButton? {
        for subView1 in subviews {
            for subView2 in subView1.subviews {
                if let cancelButton = subView2 as? UIButton {
                    return cancelButton
                }
            }
        }
        return nil
    }
}

Теперь для использования:

class MyTableViewController : UITableViewController, UISearchBarDelegate {

    var searchBar = UISearchBar()

    func viewDidLoad() {
        super.viewDidLoad()
        searchBar.delegate = self
        tableView.tableHeaderView = searchBar
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        DispatchQueue.main.async {
            if let cancelButton = searchBar.cancelButton {
                cancelButton.isEnabled = true
                cancelButton.isUserInteractionEnabled = true
            }
        }
    }
}