Question

J'ai un UISearchBar qui agit comme un filtre en direct pour une vue de tableau. Lorsque le clavier est rejeté par endEditing :, le texte de la requête et le bouton « clair » gris circulaire restent. A partir de là, si je tape sur le bouton « clair » gris du clavier réapparaît que le texte est effacé.

Comment puis-je éviter cela? Si le clavier est pas actuellement, je veux que le bouton pour effacer le texte sans rouvrir le clavier.

Il existe une méthode de protocole qui est appelé quand je tape sur le bouton clair. Mais l'envoi du UISearchBar un message resignFirstResponder n'a pas d'effet sur le clavier.

Était-ce utile?

La solution

Ceci est une vieille question et je ne suis tombé sur la même question et a réussi à le résoudre de la manière suivante:

Lorsque la méthode searchBar:textDidChange: du UISearchBarDelegate est appelée à cause de l'utilisateur appuyant sur le bouton « claire », la barre de recherche n'a pas devenir le premier répondeur encore, afin que nous puissions profiter de ce afin de détecter lorsque l'utilisateur en fait destiné à effacer la recherche et ne pas attirer l'attention sur la barre de recherche et / ou faire autre chose.

Pour garder une trace de cela, nous devons déclarer une BOOL Ivar dans notre viewController qui est aussi le délégué SearchBar (appelons-le shouldBeginEditing) et définissez avec une valeur initiale de YES (en supposant que notre classe viewController est appelée 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

Par la suite, dans le UISearchBarDelegate, nous mettons en œuvre les méthodes de searchBar:textDidChange: et 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;
}

En fait, c'est tout.

Best

Autres conseils

J'ai trouvé que resignFirstResponder ne fonctionne pas lorsque textDidChange est appelé à partir d'une touche au bouton « clair ». Cependant, l'utilisation performSelection: withObject: afterDelay: semble être une solution 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];   
}

J'ai trouvé un moyen assez sûr de savoir si le bouton a été pressé clair, et ignorer les moments où l'utilisateur vient effacer le dernier caractère du UISearchBar. Ici, il est:

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

Assez simple et direct, non :)? La seule chose à noter est que si l'utilisateur clique sur le bouton d'effacement lors de l'édition UITextField du UISearchBar, vous aurez deux pings, alors vous aurez un seul si l'utilisateur clique dessus quand il est pas en cours d'édition.


Edit: Je ne peux pas tester, mais voici la version rapide, comme par 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 !")
    }
}

@ mise à jour de 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!")
    }
}

J'ai utilisé une combinaison de la réponse de @ Boliva et aussi @ répondre à une autre question 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 meilleure solution de mon expérience est juste de mettre un UIButton (avec un fond clair et sans texte) au-dessus du bouton de système clair et que connecter un IBAction

Avec son autolayout juste plus 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];

}

En appuyant sur le bouton « clear » dans un UISearchBar ouvre automatiquement le clavier même si vous appelez searchBar.resignFirstResponder() dans la méthode de UISearchBarDelegate de textDidChange.

Pour masquer effectivement le clavier lorsque vous appuyez sur le « x » pour effacer le UISearchBar, utilisez le code suivant. De cette façon, même si textDidChange est appelé en tapant quelque chose dans le UISearchBar, vous cacher que le clavier si vous supprimez tout le texte en son sein, le temps que vous utilisez le bouton Supprimer ou vous cliquez sur le « 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.
        }
    }
}

Dans la méthode endEditing, pourquoi ne pas vous videz le UISearchBar et là? Puisque cela doit être là où vous démissionnez premier intervenant aussi, il est logique.

des appels délégués barre de recherche vous demande d'accepter un changement d'une ancienne valeur à une nouvelle - vous pouvez détecter que la nouvelle valeur était nulle, ainsi que l'ancienne valeur étant non nulle, et un indicateur que la l'utilisateur n'a pas tapé quoi que ce soit depuis le clavier dernière mise à jour - alors dans ce cas la démission premier intervenant pour la barre de recherche. Je ne sais pas si le clavier affiche un instant bien.

J'ai une situation très similaire et peut essayer moi-même.

Toucher les résultats des boutons clairs dans searchText être vide. Une autre façon d'y parvenir est de vérifier un texte vide dans - (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;
}

Pour ceux utilisant le UISearchController iOS 8 et, vous aurez envie de sous-classe simplement le UISearchController. Pour être complet, vous pouvez également cacher la Annuler bouton, comme je l'ai fait, depuis le texte de compensation de la UISearchBar est effectivement une annulation sur la recherche. J'ai ajouté que le code ci-dessous si vous voulez l'utiliser.

L'avantage est que vous serez en mesure d'utiliser pour toute classe et tout point de vue, plutôt que d'exiger une sous-classe de UIViewController. Je vais même inclure comment j'initialiser mon UISearchController au bas de cette solution.

FJSearchBar

Cette classe ne doit être surchargée si vous souhaitez masquer le bouton d'annulation comme je l'ai fait. Le marquage searchController.searchBar.showsCancelButton = NO ne semble pas fonctionner dans iOS 8 . Je ne l'ai pas testé iOS 9 .

FJSearchBar.h

vide, mais placé ici pour être complet.

@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

Voici où vous voulez faire des changements réels. Je partage le UISearchBarDelegate dans sa propre catégorie parce que, à mon humble avis, les catégories rendent les classes plus propres et plus faciles à entretenir. Si vous voulez garder le délégué au sein de la principale interface de classe / mise en œuvre, vous êtes plus que bienvenus pour le faire.

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

Certaines parties à noter:

  1. J'ai mis la barre de recherche et BOOL comme variables privées au lieu des propriétés car
    • Ils sont plus légers que les propriétés privées.
    • Ils ne doivent pas nécessairement être vu ou modifié par le monde extérieur.
  2. Nous vérifions si le searchBar est le premier intervenant. Si ce n'est pas, alors nous désactivons en fait le contrôleur de recherche parce que le texte est vide et nous ne sommes plus la recherche. Si vous vraiment voulez être sûr, vous pouvez également faire en sorte que searchText.length == 0.
  3. searchBar:textDidChange: est invoquée avant searchBarShouldBeginEditing:, ce qui est la raison pour laquelle nous avons traité dans cet ordre.
  4. mettre à jour les résultats de la recherche à chaque fois que le texte change, mais vous pouvez déplacer le [self.searchResultsUpdater updateSearchResultsForSearchController:self]; à searchBarSearchButtonClicked: si vous souhaitez que la recherche effectuée après que l'utilisateur appuie sur la Rechercher bouton .

Une version Swift de la réponse de l » @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
    }
}

J'ai rencontré plusieurs fois maintenant. J'apprécie vraiment les réponses que les gens ont donné.

En fin de compte, je voudrais vraiment voir Apple vient de nous permettre (les développeurs) pour détecter lorsque le bouton d'effacement a été enfoncé.

Il est évident que la nouvelle pression se détecté parce que tout texte dans la zone de recherche est effacé.

Je suppose que ce n'est pas très élevé sur leur liste de priorités en ce moment ... Mais je souhaite vraiment que quelqu'un chez Apple donnerait UISearchBar un peu d'amour!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top