Annuler UISearchBar lorsque l'utilisateur appuie sur la vue
Personne ne sait comment annuler (démissionner First Responder) d'un UISearchBar lorsque vous appuyez sur au-dessous de la zone de texte de recherche, et au-dessus du clavier? Quelqu'un peut-il aider à poster un peu de code pour gérer cela?
Une alternative idée que j'ai eu de iphonedevbook, des exemples de code projet 04, a été d'utiliser un seul gros bouton transparent qui se trouve derrière toutes les autres commandes qui ne fait rien, mais démissionner tous les premiers intervenants, si exploité. I. e. si l'utilisateur appuie à un endroit où il n'y a pas plus de contrôle important - ce qui est le comportement intuitif - la barre de recherche et le clavier disparaître.
C'est effectivement la même que ma suggestion ci-dessus. Il pourrait être un peu plus simple à mettre en œuvre.
Merci Hauke! Création du bouton transparent et la gestion de l'événement touchup de démissionner le premier intervenant a fait le tour.
Une autre question, j'ai maintenant est disons que j'ai une vue contenant une mkmapview derrière ce bouton transparent. Comment puis-je réactiver la carte une fois la barre de recherche a disparu?
Je suppose que ce n'est pas pertinente - mais pour d'autres qui sont intéressés:vous pouvez détecter appuyez sur la Carte à l'aide de UITapGestureRecognizer, et alors vous n'avez pas besoin d'utiliser un bouton à tous: UITapGestureRecognizer *taprec = [[UITapGestureRecognizer alloc] initWithTarget:auto action:@selector(handleTap)]; [Carte addGestureRecognizer:taprec];
Ce code a de sens, si self est un UIView. Mais la plupart du temps, self est en fait un UIViewController, ce qui devrait vraiment être [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self.searchBar action:@selector(resignFirstResponder)]];
Le code est un nu, mais vous pouvez voir le but. Lorsque la barre de recherche commence à modifier, vous fixez un robinet geste de reconnaissance à la vue du contrôleur de la vue, et l'enlever quand il cesse de l'édition.
Il y a quelques mises en garde que vous pouvez travailler autour de: faire de cette manière si vous cliquez sur autre chose que le clavier ou la barre de recherche du champ de texte, la reconnaissance des pièges du clic, donc si vous utilisez les effacer, annuler, de la portée et des résultats qu'elles ne réagissent pas correctement.
Dans mon scénario, j'ai eu un UITableView qui couvrait la surface exposée de la vue, de sorte que j'ai joint le geste de reconnaissance de la place de la vue des contrôleurs de vue principale, l'isolement de la zone à laquelle le geste allait répondre.
J'ai fini à l'aide d'un hybride de Hauke et Beau Scott approche. Il y avait deux problèmes que j'ai rencontrés en utilisant leurs solutions:
1) Si il n'y a rien d'autre sur l'écran, appuyez sur, elle ne se traduira pas par resignFirstResponder d'être appelé. Par exemple, si l'utilisateur appuie sur un bouton plutôt que de l'espace autour du bouton, le bouton de manger de l'événement. Beau Scott solution traite de cette question, cependant.
2) en Appuyant sur la barre de recherche elle-même entraînera resignFirstResponder appelé. Il est clair que vous ne souhaitez pas que le clavier disparaît lorsque vous appuyez sur UISearchBar. Un petit changement décrit ci-dessous porte sur cette question.
J'ai fini par mettre en place mon point de vue comme suit. La vue parent de deux enfants - la UISearchBar et une sous-vue qui détient le reste de ma éléments de l'INTERFACE utilisateur. La sous-vue prend la totalité de l'écran en dessous de la UISearchBar. Ensuite, j'ai utilisé le Beau Scott exact de code permettant d'ajouter et de supprimer le geste de reconnaissance, mais au lieu d'ajouter à l'auto.vue je l'ai ajouté à la sous-vue:
Tout d'abord, vous avez besoin d'une référence, la barre de recherche. Supposons que votre contrôleur de l'objet a une référence d'objet UISearchBar *theSearchBar, et que vous attribuez au moment de créer la UISearchBar objet.
Ensuite, vous avez besoin de détecter que le contenant a été touché. Le point de vue qui est touché "sait", mais vous avez besoin d'obtenir que des informations sur le contrôleur. Malheureusement, Apple ne fournit pas un moyen simple de faire cela, mais il n'est pas difficile non plus.
Ma solution est de remplacer la norme UIView qu'un UIViewController objet crée normalement avec un UIControl, et ensuite faire le UIViewController répondre à des événements tactiles.
MainController.m
-(void) loadView {UIControl*control =[[UIControl alloc] initWithFrame:<desired frame>];[control addTarget: self action:@selector(touchUpInside)
forControlEvents:UIControlEventTouchUpInside];//or touch down events, or whatever you like
self.view = control;[control release];}-(void) viewDidLoad {[super viewDidLoad];
theSearchBar =[[UISearchBar alloc] initWithFrame:<desired frame>];//insert code to finish customizing the search bar[self.view addSubview: theSearchBar];}-(void) touchUpInside {if[theSearchBar isFirstResponder]{//grab any data you need from the search bar[theSearchBar resignFirstResponder];}}
Il n'existe qu'un seul objet -- appelons la classe MainController -- qui est une sous-classe de UIViewController. Toutes les méthodes énumérées ci-dessus sont mis en œuvre dans MainController. theSearchBar est déclaré comme un UISearchBar* dans la .h fichier.
Êtes-vous définir votre point de vue et contrôleur à l'aide de l'Interface Builder? Si si, je vous suggère d'apprendre à ne PAS l'utiliser, une fois que vous obtenez dans le genre de trucs que nous discutons ici, il devient de plus en plus un fardeau qu'une aide, je ne l'utilise pas du tout, jamais.
Comment puis-je obtenir la référence à la barre de recherche de la touchUpInside événement? J'ai touchUpInside dans le viewcontroller classe contenant la barre de recherche.
Tu veux dire, pour invoquer resignFirstResponder? Vous l'avez déjà si vous avez enregistré comme référence lorsque vous l'avez créé.
Je suis un peu confus. Est le code ci-dessus censé être dans une vue séparée contrôleur de celui où j'ai créé la barre de recherche? Pourquoi voulez-vous créer une UIControl au lieu d'un UISearchBar dans votre loadView routine?
Oui, vous êtes confus, et probablement parce que je n'ai pas mis assez de code pour vous. Je vais modifier ma réponse.
Merci pour plus de détails. J'ai essayé de suivre votre mise à jour très particulier, mais maintenant j'obtiens le message d'erreur: erreur: 'barre de recherche' non déclaré (première utilisation dans cette fonction). Pour info, barre de recherche est le nom de la UISearchBar *barre de recherche a déclaré dans mon viewDidLoad événement. Dois-je déclarer la barre de recherche à l'échelle mondiale?
Pas globalement, mais dans le MainController.h de fichier (ou ce que vous appelez). Je mettrai juste un peu plus au-dessus de vous montrer ce que je veux dire; cependant, si VRAIMENT vous ne comprenez pas cela, je pense que vous avez besoin de lire la documentation dans un peu plus en détail.
Je l'ai déjà fait toutes les choses que vous avez mentionnées. Maintenant, quand je créer et exécuter, il est dit de charger plus d'une centaine de milliers de pile d'images. Le débogueur sauts à certaines machines d'assemblage et le simulateur affiche un écran noir. Quand j'en commentaire votre loadView routine ci-dessus, il fonctionne très bien. Veuillez informer.
Il a à voir avec la façon dont vous êtes l'attribution de soi.vue dans loadView. J'ai besoin de double-vérifier la syntaxe -- merci de me donner un peu de le faire.
Duh. J'ai fait une stupide erreur. viewDidLoad a pas de paramètres -- c'est seulement ceux qui, comme viewDidAppear, etc. qui ont "animé" comme paramètre. Essayez de fixation comme indiqué ci-dessus.
J'ai essayé, mais je suis toujours une exception. Je suis en utilisant le sdk de l'iphone 3.0.
Bon, à ce stade, j'ai besoin de voir votre code. Sinon, il n'y a pas beaucoup que je peux faire.
Est-il un e-mail je peux vous envoyer mon code?
Je préfère ne pas poster mon e-mail ici. Serait-il vraiment si mauvais poste juste les méthodes qui sont impliqués?
@Gia Dang est la réponse la plus simple, mais je n'ai pas de sous-classe UIView, seul le UIViewController, donc mon appel est légèrement différents. Aussi, puisque je ne connais pas les frais généraux de l'appelant resignFirstResponder, je préfère vérifier d'abord. C'est plus de code, mais depuis que tout cela est fait sur le thread principal (ce qui peut ralentir l'INTERFACE utilisateur), je préfère vérifier d'abord.
@implementationMyController:UIViewController{@privateUISearchController*_uiSearchController;}-(void)viewDidLoad {//add tap on view to resign the responder if we're in the middle of typing in the searchUITapGestureRecognizer*tapGestureRecognizer =[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboardIfNeeded)];[self.view addGestureRecognizer:tapGestureRecognizer];}-(void)closeKeyboardIfNeeded {if(![_uiSearchController.searchBar isFirstResponder]){return;}[_uiSearchController.searchBar resignFirstResponder];}@end
Comme pour les autres réponses, veillez constamment à recréer des objets. Il y a toujours une dégradation des performances, que c'est la création elle-même ou de la collecte des déchets par le biais de ARC, et ces choses vont ralentir votre thread principal. En fonction de ce que vous faites aussi sur le thread principal, il peut avoir un impact significatif sur les performances.
Une alternative idée que j'ai eu de iphonedevbook, des exemples de code projet 04, a été d'utiliser un seul gros bouton transparent qui se trouve derrière toutes les autres commandes qui ne fait rien, mais démissionner tous les premiers intervenants, si exploité. I. e. si l'utilisateur appuie à un endroit où il n'y a pas plus de contrôle important - ce qui est le comportement intuitif - la barre de recherche et le clavier disparaître.
Ajouter un robinet geste de la vue parent (de la UISearchbar)
self
est unUIView
. Mais la plupart du temps,self
est en fait unUIViewController
, ce qui devrait vraiment être[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self.searchBar action:@selector(resignFirstResponder)]];
Je l'ai accompli à l'aide d'un UITapGestureRecognizer:
Le code est un nu, mais vous pouvez voir le but. Lorsque la barre de recherche commence à modifier, vous fixez un robinet geste de reconnaissance à la vue du contrôleur de la vue, et l'enlever quand il cesse de l'édition.
Il y a quelques mises en garde que vous pouvez travailler autour de: faire de cette manière si vous cliquez sur autre chose que le clavier ou la barre de recherche du champ de texte, la reconnaissance des pièges du clic, donc si vous utilisez les effacer, annuler, de la portée et des résultats qu'elles ne réagissent pas correctement.
Dans mon scénario, j'ai eu un UITableView qui couvrait la surface exposée de la vue, de sorte que j'ai joint le geste de reconnaissance de la place de la vue des contrôleurs de vue principale, l'isolement de la zone à laquelle le geste allait répondre.
J'ai fini à l'aide d'un hybride de Hauke et Beau Scott approche. Il y avait deux problèmes que j'ai rencontrés en utilisant leurs solutions:
1) Si il n'y a rien d'autre sur l'écran, appuyez sur, elle ne se traduira pas par resignFirstResponder d'être appelé. Par exemple, si l'utilisateur appuie sur un bouton plutôt que de l'espace autour du bouton, le bouton de manger de l'événement. Beau Scott solution traite de cette question, cependant.
2) en Appuyant sur la barre de recherche elle-même entraînera resignFirstResponder appelé. Il est clair que vous ne souhaitez pas que le clavier disparaît lorsque vous appuyez sur UISearchBar. Un petit changement décrit ci-dessous porte sur cette question.
J'ai fini par mettre en place mon point de vue comme suit. La vue parent de deux enfants - la UISearchBar et une sous-vue qui détient le reste de ma éléments de l'INTERFACE utilisateur. La sous-vue prend la totalité de l'écran en dessous de la UISearchBar. Ensuite, j'ai utilisé le Beau Scott exact de code permettant d'ajouter et de supprimer le geste de reconnaissance, mais au lieu d'ajouter à l'auto.vue je l'ai ajouté à la sous-vue:
...
Tout d'abord, vous avez besoin d'une référence, la barre de recherche. Supposons que votre contrôleur de l'objet a une référence d'objet UISearchBar *theSearchBar, et que vous attribuez au moment de créer la UISearchBar objet.
Ensuite, vous avez besoin de détecter que le contenant a été touché. Le point de vue qui est touché "sait", mais vous avez besoin d'obtenir que des informations sur le contrôleur. Malheureusement, Apple ne fournit pas un moyen simple de faire cela, mais il n'est pas difficile non plus.
Ma solution est de remplacer la norme UIView qu'un UIViewController objet crée normalement avec un UIControl, et ensuite faire le UIViewController répondre à des événements tactiles.
MainController.m
MainController.h
Précisions:
Il n'existe qu'un seul objet -- appelons la classe MainController -- qui est une sous-classe de UIViewController. Toutes les méthodes énumérées ci-dessus sont mis en œuvre dans MainController. theSearchBar est déclaré comme un UISearchBar* dans la .h fichier.
Êtes-vous définir votre point de vue et contrôleur à l'aide de l'Interface Builder? Si si, je vous suggère d'apprendre à ne PAS l'utiliser, une fois que vous obtenez dans le genre de trucs que nous discutons ici, il devient de plus en plus un fardeau qu'une aide, je ne l'utilise pas du tout, jamais.
@Gia Dang est la réponse la plus simple, mais je n'ai pas de sous-classe
UIView
, seul leUIViewController
, donc mon appel est légèrement différents. Aussi, puisque je ne connais pas les frais généraux de l'appelantresignFirstResponder
, je préfère vérifier d'abord. C'est plus de code, mais depuis que tout cela est fait sur le thread principal (ce qui peut ralentir l'INTERFACE utilisateur), je préfère vérifier d'abord.Comme pour les autres réponses, veillez constamment à recréer des objets. Il y a toujours une dégradation des performances, que c'est la création elle-même ou de la collecte des déchets par le biais de ARC, et ces choses vont ralentir votre thread principal. En fonction de ce que vous faites aussi sur le thread principal, il peut avoir un impact significatif sur les performances.