Uisearchbar clearButton wymusza wyświetlanie klawiatury

Mam Pasek Uisearch, który działa jako aktywny filtr dla widoku tabeli. Gdy klawiatura zostanie odrzucona przez endEditing:, tekst zapytania i szary okrągły przycisk "Wyczyść" pozostają. Od tego miejsca, jeśli dotknę szarego przycisku "Wyczyść", klawiatura pojawi się ponownie, gdy tekst zostanie wyczyszczony.

Jak temu zapobiec? Jeśli klawiatura nie jest obecnie otwarta, chcę, aby ten przycisk wyczyścił tekst bez ponownego otwierania klawiatury.

Istnieje metoda protokołu, która zostanie wywołana, gdy dotknę Wyczyść guzik. Ale wysyłanie paska UISearchBar wiadomości recipfirstresponder nie ma żadnego wpływu na klawiaturę.

Author: Stephan, 2009-07-07

12 answers

To stare pytanie i właśnie natknąłem się na ten sam problem i udało mi się rozwiązać go w następujący sposób: {]}

Kiedy searchBar:textDidChange: metoda UISearchBarDelegate zostanie wywołana z powodu naciśnięcia przycisku "Wyczyść", pasek wyszukiwania nie stał się jeszcze pierwszym responsorem, więc możemy skorzystać z tego, aby wykryć, kiedy użytkownik faktycznie zamierzał wyczyścić wyszukiwanie, a nie skupić się na pasku wyszukiwania i / lub zrobić coś innego.

Aby to śledzić, musimy zadeklaruj BOOL ivar w naszym viewcontrolle, który jest również delegatem searchBar (nazwijmy go shouldBeginEditing) i ustaw go z wartością początkową YES (przypuśćmy, że nasza klasa ViewController nazywa się 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

Później w UISearchBarDelegate zaimplementujemy metody searchBar:textDidChange: i 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;
}

W Zasadzie, to wszystko.

Najlepsze

 120
Author: boliva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-04 02:36:41

Odkryłem, że resignFirstResponder nie działa, gdy textDidChange jest wywoływany od dotknięcia do "wyczyść przycisk". Jednak użycie performSelection: withObject: afterDelay: wydaje się być skutecznym obejściem:

- (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];   
}
 33
Author: Gregory Cosmo Haun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-12 22:22:00

Znalazłem dość bezpieczny sposób, aby wiedzieć, czy przycisk Wyczyść został naciśnięty, i zignorować czasy, kiedy użytkownik po prostu usunąć ostatni znak paska Uisearch. Tutaj jest:

- (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 !");
    }
}

Dość proste i proste, czyż nie :) ? Jedyne, co należy zauważyć, to to, że jeśli użytkownik kliknie przycisk Wyczyść podczas edycji pola UITextField paska Uisearch, będziesz miał dwa pingi, podczas gdy otrzymasz tylko jeden, jeśli użytkownik kliknie go, gdy nie jest edytowany.


Edytuj : Nie mogę przetestować to, ale tu jest wersja swift, jak na 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 ' s update (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!")
    }
}
 9
Author: CyberDandy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-06 13:28:43

Użyłem kombinacji odpowiedzi @boliva i również @radiospiel Odpowiedź na inne pytanie 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
 8
Author: benvolioT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:22

Najlepszym rozwiązaniem z mojego doświadczenia jest po prostu umieścić UIButton (z czystym tłem i bez tekstu) nad przyciskiem Wyczyść system i następnie podłączyć IBAction

Z autolayout jest po prostu więcej niż łatwe

- (IBAction)searchCancelButtonPressed:(id)sender {

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

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

}
 3
Author: Peter Lapisu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-10 12:19:34

W metodzie endEditing, dlaczego nie wyczyścisz paska UISearchBar i tam? Ponieważ to musi być miejsce, w którym rezygnujesz z pierwszej odpowiedzi, to ma sens.

 0
Author: Corey Floyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-07 13:36:51

Of The search bar delegate calls prosi Cię o zaakceptowanie zmiany ze starej wartości na nową - możesz wykryć, że nowa wartość była zerowa, wraz ze starą wartością nie jest-nil, i wskaźnik, że użytkownik nie wpisał niczego od czasu, gdy klawiatura była ostatnia - następnie w takim przypadku Zrezygnuj z pierwszej odpowiedzi na pasek wyszukiwania. Nie jestem pewien, czy klawiatura będzie chwilowo wyświetlana.

Mam bardzo podobną sytuację i sam mogę spróbować.

 0
Author: Kendall Helmstetter Gelner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-07 15:47:06

Dotknięcie przycisku Wyczyść powoduje, że searchText jest puste. Innym sposobem, aby to osiągnąć, jest sprawdzenie pustego tekstu w - (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;
}
 0
Author: H K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-12 01:55:53

Dla tych z Was, którzy używają UISearchController w iOS 8 i w górę, po prostu podklasuj UISearchController. Dla kompletności, możesz również ukryć przycisk anuluj , tak jak ja, ponieważ wyczyszczenie tekstu z {[6] } jest skutecznie Anuluj w wyszukiwaniu. Dodałem ten kod poniżej, jeśli chcesz go użyć.

Zaletą tego jest to, że będziesz mógł używać tego dla dowolnej klasy i dowolnego widoku, zamiast wymagać podklasy UIViewController. Będę nawet zawierać jak initialize mój UISearchController na dole tego rozwiązania.

FJSearchBar

Ta klasa musi być nadpisana tylko wtedy, gdy chcesz ukryć przycisk Anuluj, tak jak ja. Znakowanie searchController.searchBar.showsCancelButton = NO wydaje się nie działać w iOS 8. Nie testowałem iOS 9.

FJSearchBar.h

Puste, ale umieszczone tutaj dla kompletności.

@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

Tutaj chcesz wprowadzić prawdziwe zmiany. Podzieliłem UISearchBarDelegate na własna Kategoria, bo IMHO kategorie sprawiają, że klasy są czystsze i łatwiejsze w utrzymaniu. Jeśli chcesz zachować delegata w głównym interfejsie/implementacji klas, możesz to zrobić.

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

Niektóre części do zapamiętania:

  1. umieściłem pasek wyszukiwania i BOOL jako prywatne zmienne zamiast właściwości, ponieważ
    • są bardziej lekkie niż prywatne właściwości.
    • Nie muszą być postrzegane ani modyfikowane przez świat zewnętrzny.
  2. sprawdzamy, czy {[12] } jest pierwszą osobą odpowiedzialną. Jeśli tak nie jest, to faktycznie dezaktywujemy kontroler wyszukiwania, ponieważ tekst jest pusty i nie szukamy już. Jeśli naprawdę chcesz mieć pewność, możesz również to zapewnić.
  3. {[14] } jest wywoływany przed searchBarShouldBeginEditing:, dlatego wykonaliśmy go w tej kolejności.
  4. aktualizuję wyniki wyszukiwania za każdym razem tekst zmienia się, ale możesz przenieść [self.searchResultsUpdater updateSearchResultsForSearchController:self]; do searchBarSearchButtonClicked:, jeśli chcesz, aby wyszukiwanie było wykonywane tylko po naciśnięciu przez użytkownika przycisku Search.
 0
Author: mikeho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-06 00:59:29

Szybka wersja odpowiedzi @ 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
    }
}
 0
Author: swordray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-25 21:11:53

Naciśnięcie przycisku "Wyczyść" w pasku UISearchBar automatycznie otworzy klawiaturę, nawet jeśli wywołasz searchBar.resignFirstResponder() w ramach metody textDidChange UISearchBarDelegate.

Aby ukryć klawiaturę po naciśnięciu "x", aby wyczyścić Pasek Uisearch, użyj poniższego kodu. W ten sposób, nawet jeśli textDidChange zostanie wywołana podczas wpisywania czegoś w pasku UISearchBar, ukrywasz klawiaturę tylko wtedy, gdy usuniesz cały tekst w niej zawarty, użyjesz przycisku delete lub klikniesz "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.
        }
    }
}
 0
Author: luismgb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-19 19:55:38

Wpadłem na to już kilka razy. Naprawdę doceniam odpowiedzi, które ludzie dali.

Ostatecznie, naprawdę chciałbym, aby Apple po prostu pozwolić nam (deweloperom) wykryć, kiedy przycisk Wyczyść został naciśnięty.

Jest oczywiste, że naciśnięcie go zostanie wykryte, ponieważ dowolny tekst w polu wyszukiwania zostanie wyczyszczony.

Zgaduję, że to nie jest teraz zbyt wysoko na ich liście priorytetów... Ale naprawdę chciałbym, żeby ktoś z Apple dał UISearchBar a little love!

 -1
Author: user3096669,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-12 14:05:57