UISearchBar отключить автоматическое отключение кнопки отмены - PullRequest
36 голосов
/ 03 декабря 2010

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

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

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

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

Ответы [ 10 ]

51 голосов
/ 03 декабря 2010

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

for (UIView *possibleButton in searchBar.subviews)
{
    if ([possibleButton isKindOfClass:[UIButton class]])
    {
        UIButton *cancelButton = (UIButton*)possibleButton;
        cancelButton.enabled = YES;
        break;
    }
}
15 голосов
/ 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;
            }
        }
    }
}
5 голосов
/ 13 января 2015

Существует два способа легко это сделать.

- (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 и без изменений, а также без проблем использую его в своем утвержденном Магазине приложении.

3 голосов
/ 13 января 2014

Вот мое решение, которое работает во всех ситуациях во всех версиях 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's 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];
3 голосов
/ 01 ноября 2012

Вот что заставило его работать на iOS 6 для меня:

searchBar.showsCancelButton = YES;
searchBar.showsScopeBar = YES;
[searchBar sizeToFit];
[searchBar setShowsCancelButton:YES animated:YES];
2 голосов
/ 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);
    });
}
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, но какого черта. Пока работает.

1 голос
/ 08 апреля 2017

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

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
            }
        }
    }
}
1 голос
/ 04 декабря 2016

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

  • , начиная с iOS 7, есть дополнительный уровень подпредставлений под строкой поиска
  • . Хорошее место для включения кнопки отмены - 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
        }
      })
    }
  }
}
1 голос
/ 09 января 2015

Для Monotouch или Xamarin iOS у меня есть следующее решение C #, работающее для 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;
            }
        }
    }
}

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

...