Domanda

Ho un UISearchBar che agisce come un filtro attivo per una visualizzazione della tabella. Quando la tastiera è respinto tramite endEditing :, il testo della query e il pulsante grigio circolare "chiaro" rimangono. Da qui, se si tocca il pulsante grigio "clear", la tastiera riappare come il testo viene cancellato.

Come posso evitare questo? Se la tastiera non è aperto voglio che il pulsante per cancellare il testo senza riaprire la tastiera.

C'è un metodo di protocollo che viene chiamato quando si tocca il pulsante chiaro. Ma l'invio del UISearchBar un messaggio resignFirstResponder non ha alcun effetto sulla tastiera.

È stato utile?

Soluzione

Questa è una vecchia questione e ho appena imbattuto lo stesso problema ed è riuscito a risolverlo nel seguente modo:

Quando il metodo searchBar:textDidChange: del UISearchBarDelegate viene chiamato a causa del l'utente toccando il pulsante 'chiaro', la barra di ricerca, non è diventato ancora il primo soccorritore, in modo che possiamo approfittare di questo, al fine di rilevare quando l'utente di fatto destinato a cancellare la ricerca e non portare attenzione alla barra di ricerca e / o di fare qualcosa di diverso.

Per tenere traccia di ciò, abbiamo bisogno di dichiarare un'Ivar BOOL nel nostro viewController che è anche il delegato Searchbar (chiamiamolo shouldBeginEditing) e impostare con un valore iniziale di YES (supponendo la nostra classe viewController si chiama 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

In seguito, nel UISearchBarDelegate, implementiamo i metodi searchBar:textDidChange: e 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;
}

In sostanza, questo è tutto.

Best

Altri suggerimenti

Ho trovato che resignFirstResponder non funziona quando textDidChange viene chiamato da un tocco al pulsante "Clear". Tuttavia, utilizzando performSelection: withObject: afterDelay: sembra essere una soluzione efficace:

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

Ho trovato un modo abbastanza sicuro di sapere se il pulsante è stato premuto chiara, e ignorare i tempi in cui l'utente basta cancellare l'ultimo carattere del UISearchBar. Eccolo:

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

Piuttosto semplice e lineare, non è vero :)? L'unica cosa da notare è che se l'utente fa clic sul pulsante Cancella durante la modifica UITextField del UISearchBar, si avranno due ping, mentre si otterrà un solo se l'utente fa clic quando non è in fase di modifica.


Modifica: Non posso provarlo, ma ecco la versione rapida, come da 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 !")
    }
}

@ aggiornamento di 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!")
    }
}

Ho usato una combinazione di risposta di @ Boliva ed anche @ rispondo ad una domanda diversa 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

La migliore soluzione dalla mia esperienza è solo quello di mettere un UIButton (con sfondo chiaro e senza testo) al di sopra del pulsante di azzeramento sistema e di collegare un IBAction

Con la sua autolayout poco più di facile

- (IBAction)searchCancelButtonPressed:(id)sender {

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

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

}

Premendo il tasto "clear" in un UISearchBar si apre automaticamente la tastiera, anche se si chiama searchBar.resignFirstResponder() all'interno del metodo textDidChange UISearchBarDelegate.

Per nascondere in realtà la tastiera quando si preme il tasto "x" per cancellare l'UISearchBar, utilizzare il seguente codice. In questo modo, anche se textDidChange viene chiamato durante la digitazione qualcosa nel UISearchBar, si nasconde solo la tastiera se si elimina tutto il testo all'interno di esso, il tempo si utilizza il tasto di cancellazione o si sceglie la "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.
        }
    }
}

Nel tuo metodo endEditing, perché non si cancella l'UISearchBar e là? Dal momento che deve essere dove ti dimetti first responder anche, ha senso.

delle chiamate barra di ricerca del delegato si chiede di accettare un passaggio da un vecchio valore ad uno nuovo - si può rilevare che il nuovo valore era pari a zero, insieme con il vecchio valore non essendo a zero, e un indicatore che il utente non aveva digitato nulla dal momento che la tastiera era ultima in su - allora in quel caso le dimissioni first responder per la barra di ricerca. Non sono sicuro se la tastiera visualizzerà momentaneamente però.

Ho una situazione molto simile e può provare anch'io.

Toccando i risultati tasto CLEAR searchText essere vuota. Un altro modo per raggiungere questo obiettivo è quello di verificare la presenza di testo vuoto in - (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;
}

Per quelli di voi che usano il UISearchController in iOS 8 e su, ti consigliamo di creare una sottoclasse semplicemente il UISearchController. Per completezza, si potrebbe anche voler nascondere il Annulla tasto, come ho fatto io, dal momento che la compensazione il testo dal UISearchBar è effettivamente un annullare sulla ricerca. Ho aggiunto che il codice qui sotto, se si desidera utilizzarlo.

Il vantaggio di questo è che sarete in grado di utilizzare questo per qualsiasi classe e qualsiasi vista, piuttosto che richiedere una sottoclasse di UIViewController. Io anche includere come ho inizializzare il mio UISearchController in fondo a questa soluzione.

FJSearchBar

Questa classe ha solo bisogno di essere ignorata se si desidera nascondere il pulsante Annulla come ho fatto io. Marcatura searchController.searchBar.showsCancelButton = NO non sembra funzionare in iOS 8 . Non ho ancora testato iOS 9 .

FJSearchBar.h

Vuoto, ma posto qui per completezza.

@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

Ecco dove si vuole fare i veri cambiamenti. Ho diviso il UISearchBarDelegate nella propria categoria, perché, secondo me, le categorie fanno le classi più pulito e più facile da mantenere. Se si desidera mantenere il delegato all'interno della principale interfaccia di classe / implementazione, siete più che benvenuti a farlo.

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

Alcune parti da notare:

  1. Ho messo la barra di ricerca e la BOOL come variabili private invece di proprietà a causa
    • Sono più leggero di proprietà private.
    • non hanno bisogno di essere visto o modificato dal mondo esterno.
  2. verificare se la searchBar è il primo responder. Se non lo è, allora abbiamo effettivamente disattivare il controllo di ricerca perché il testo è vuoto e noi non siamo più la ricerca. Se davvero vuole essere sicuri, si può anche assicurare che searchText.length == 0.
  3. searchBar:textDidChange: viene invocato prima searchBarShouldBeginEditing:, che è il motivo per cui abbiamo gestito in questo modo.
  4. aggiorno i risultati di ricerca ogni volta che il testo cambia, ma si consiglia di spostare il [self.searchResultsUpdater updateSearchResultsForSearchController:self]; per searchBarSearchButtonClicked: se desideri solo la ricerca eseguita dopo che l'utente preme il ricerca pulsante.

Una versione Swift di risposta s' @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
    }
}

Ho eseguito in questo diverse volte. Apprezzo molto le risposte che la gente ha dato.

In definitiva, mi piacerebbe davvero vedere Apple ha appena noi (gli sviluppatori) permettono di rilevare quando è stato premuto il pulsante Cancella.

E 'ovvio che la pressione che venga rilevato perché qualsiasi testo nella casella di ricerca viene cancellata.

Sono indovinando che semplicemente non è molto in alto nella loro lista di priorità in questo momento ... Ma ho davvero che qualcuno di Apple darebbe UISearchBar un po 'd'amore!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top