Вопрос

У меня есть UISearchBar, который действует как живой фильтр для табличного представления.Когда клавиатура отключается с помощью endEditing:, текст запроса и серая круглая кнопка "Очистить" остаются.Отсюда, если я нажму серую кнопку "Очистить", клавиатура снова появится, когда текст будет очищен.

Как мне предотвратить это?Если клавиатура в данный момент не открыта, я хочу, чтобы эта кнопка очищала текст без повторного открытия клавиатуры.

Существует метод протокола, который вызывается, когда я нажимаю кнопку очистить.Но отправка UISearchBar сообщения resignFirstResponder не оказывает никакого влияния на клавиатуру.

Это было полезно?

Решение

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

Когда в searchBar:textDidChange: метод UISearchBarDelegate вызывается из-за того, что пользователь нажимает кнопку "Очистить", панель поиска еще не стала первым ответчиком, поэтому мы можем воспользоваться этим, чтобы определить, когда пользователь на самом деле намеревался очистить поиск, а не переключать внимание на панель поиска и / или делать что-то еще.

Чтобы отслеживать это, нам нужно объявить BOOL ivar в нашем ViewController, который также является делегатом панели поиска (давайте назовем его shouldBeginEditing) и установите для него начальное значение YES (предположим, наш класс ViewController называется SearchViewController):

@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;
    }
}
...
@end

Позже, в UISearchBarDelegate, мы реализуем searchBar:textDidChange: и searchBarShouldBeginEditing: методы:

- (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText {
    NSLog(@"searchBar:textDidChange: isFirstResponder: %i", [self.searchBar isFirstResponder]);
    if(![searchBar isFirstResponder]) {
        // user tapped the 'clear' button
        shouldBeginEditing = NO;
        // do whatever I want to happen when the user clears the search...
    }
}


- (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;
}

В принципе, это все.

Лучшие

Другие советы

Я обнаружил, что resignFirstResponder не работает, когда textDidChange вызывается нажатием кнопки "Очистить".Однако, используя performSelection: withObject: afterDelay: кажется, это эффективное обходное решение:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if ([searchText length] == 0) {
        [self performSelector:@selector(hideKeyboardWithSearchBar:) withObject:searchBar afterDelay:0];
    }
}

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

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

- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    _isRemovingTextWithBackspace = ([searchBar.text stringByReplacingCharactersInRange:range withString:text].length == 0);

    return YES;
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if (searchText.length == 0 && !_isRemovingTextWithBackspace)
    {
        NSLog(@"Has clicked on clear !");
    }
}

Довольно просто и прямолинейно, не правда ли :) ?Единственное, что следует отметить, это то, что если пользователь нажмет кнопку очистить при редактировании UITextField в UISearchBar, у вас будет два пинга, тогда как вы получите только один, если пользователь нажмет на него, когда оно не редактируется.


Редактировать :Я не могу это протестировать, но вот версия swift, согласно Rotem :

var isRemovingTextWithBackspace = false

func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool
{
    self.isRemovingTextWithBackspace = (NSString(string: searchBar.text!).stringByReplacingCharactersInRange(range, withString: text).characters.count == 0)
    return true
}

func searchBar(searchBar: UISearchBar, textDidChange searchText: String)
{
    if searchText.characters.count == 0 && !isRemovingTextWithBackspace
    { 
        NSLog("Has clicked on clear !")
    }
}

Обновление от @Rotem (Swift2):

var isRemovingTextWithBackspace = false

func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    self.isRemovingTextWithBackspace = (NSString(string: searchBar.text!).stringByReplacingCharactersInRange(range, withString: text).characters.count == 0)
    return true
}

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.characters.count == 0 && !isRemovingTextWithBackspace {
        NSLog("Has clicked on clear!")
    }
}

Я использовал комбинацию ответа @boliva, а также ответа @radiospiel ответ к другому вопросу SO:

@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

Лучшее решение, исходя из моего опыта, - это просто поставить UIButton (с четким фоном и без текста) над кнопкой очистки системы, а затем подключите IBAction

С автозаполнением это просто более чем просто

- (IBAction)searchCancelButtonPressed:(id)sender {

    [self.searchBar resignFirstResponder];
    self.searchBar.text = @"";

    // some of my stuff
    self.model.fastSearchText = nil;
    [self.model fetchData];
    [self reloadTableViewAnimated:NO];

}

Нажатие кнопки "очистить" на панели пользовательского поиска автоматически открывает клавиатуру, даже если вы вызываете searchBar.resignFirstResponder() в пределах textDidChange Метод UISearchBarDelegate.

Чтобы на самом деле скрыть клавиатуру, когда вы нажимаете "x", чтобы очистить панель пользовательского поиска, используйте следующий код.Таким образом, даже если textDidChange вызывается при вводе чего-либо на панели пользовательского поиска, вы скрываете клавиатуру, только если удаляете весь текст внутри нее, независимо от того, используете ли вы кнопку удаления или нажимаете "x":

extension ViewController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        if searchBar.text!.count == 0 {
            DispatchQueue.main.async {
                searchBar.resignFirstResponder()
            }
        } else {
            // Code to make a request here.
        }
    }
}

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

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

У меня очень похожая ситуация, и я могу попробовать это сам.

Нажатие кнопки очистить приводит к searchText быть пустым.Другой способ добиться этого - проверить наличие пустого текста в - (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if([searchText length] == 0)
    {
        [self dismissSearch];
    }
    else
    {
        self.searchResultsTable.hidden = YES;
        [self handleSearchForString:searchText];
    }
}

- (void)dismissSearch
{
    [self.searchBar performSelector: @selector(resignFirstResponder)
                  withObject: nil
                  afterDelay: 0.1];

    self.searchResultsTable.hidden = YES;
}

Для тех из вас, кто использует UISearchController в iOS 8 и выше, вы захотите просто подклассировать UISearchController.Для полноты картины вы также можете скрыть Отмена кнопка, как я и сделал, с момента удаления текста из UISearchBar фактически это отмена поиска.Я добавил этот код ниже, если вы хотите его использовать.

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

Панель поиска FJSearchBar

Этот класс нужно переопределить только в том случае, если вы хотите скрыть кнопку отмены, как это сделал я.Маркировка searchController.searchBar.showsCancelButton = NO похоже, это не работает в iOS 8.Я еще не проверял iOS 9.

Панель поиска FJ.h

Пусто, но помещено здесь для полноты картины.

@import UIKit;

@interface FJSearchBar : UISearchBar

@end

Панель поиска FJSearchBar.m

#import "FJSearchBar.h"

@implementation FJSearchBar

- (void)setShowsCancelButton:(BOOL)showsCancelButton {
    // do nothing
}

- (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
    // do nothing
}

@end

FJSearchController ( Поисковый контроллер )

Вот где вы хотите внести реальные изменения.Я разделил UISearchBarDelegate в свою собственную категорию, потому что, ИМХО, категории делают классы более чистыми и простыми в обслуживании.Если вы хотите сохранить делегат в основном интерфейсе / реализации класса, мы более чем рады это сделать.

FJSearchController.h

@import UIKit;

@interface FJSearchController : UISearchController

@end

@interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate>

@end

FJSearchController.m

#import "FJSearchController.h"
#import "FJSearchBar.h"

@implementation FJSearchController {
@private
    FJSearchBar *_searchBar;
    BOOL _clearedOutside;
}

- (UISearchBar *)searchBar {
    if (_searchBar == nil) {
        // if you're not hiding the cancel button, simply uncomment the line below and delete the FJSearchBar alloc/init
        // _searchBar = [[UISearchBar alloc] init];
        _searchBar = [[FJSearchBar alloc] init];
        _searchBar.delegate = self;
    }
    return _searchBar;
}

@end

@implementation FJSearchController (UISearchBarDelegate)

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
    // if we cleared from outside then we should not allow any new editing
    BOOL shouldAllowEditing = !_clearedOutside;
    _clearedOutside = NO;
    return shouldAllowEditing;
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    // hide the keyboard since the user will no longer add any more input
    [searchBar resignFirstResponder];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    if (![searchBar isFirstResponder]) {
        // the user cleared the search while not in typing mode, so we should deactivate searching
        self.active = NO;
        _clearedOutside = YES;
        return;
    }
    // update the search results
    [self.searchResultsUpdater updateSearchResultsForSearchController:self];
}

@end

Некоторые детали, на которые следует обратить внимание:

  1. Я ввел строку поиска и BOOL в качестве частных переменных вместо свойств, потому что
    • Они более легкие, чем частные владения.
    • Они не нуждаются в том, чтобы их видел или изменял внешний мир.
  2. Мы проверяем, является ли searchBar является первым ответчиком.Если это не так, то мы фактически деактивируем контроллер поиска, потому что текст пуст, и мы больше не выполняем поиск.Если вы действительно хотите быть уверены, вы также можете гарантировать, что searchText.length == 0.
  3. searchBar:textDidChange: вызывается перед searchBarShouldBeginEditing:, вот почему мы обработали это в таком порядке.
  4. Я обновляю результаты поиска каждый раз, когда меняется текст, но вы можете захотеть переместить [self.searchResultsUpdater updateSearchResultsForSearchController:self]; Для searchBarSearchButtonClicked: если вы хотите, чтобы поиск выполнялся только после того, как пользователь нажмет Поиск кнопка.

Быстрая версия ответа @boliva.

class MySearchContentController: UISearchBarDelegate {

    private var searchBarShouldBeginEditing = true

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchBarShouldBeginEditing = searchBar.isFirstResponder
    }

    func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
        defer {
            searchBarShouldBeginEditing = true
        }
        return searchBarShouldBeginEditing
    }
}

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

В конечном счете, мне бы очень хотелось, чтобы Apple просто позволила нам (разработчикам) определять, когда была нажата кнопка очистить.

Очевидно, что нажатие на нее будет обнаружено, потому что любой текст в окне поиска будет очищен.

Я предполагаю, что сейчас это просто не очень высоко в их списке приоритетов...Но я действительно хотел бы, чтобы кто-нибудь в Apple уделил UISearchBar немного любви!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top