Mon objectif est d'empêcher le bouton d'annulation d'apparaître dans une barre de recherche d'un UISearchController. J'ai commencé avec Le système de recherche de table Apple avec l'exemple de code UISearchController et ai masqué le bouton d'annulation, comme indiqué dans le code ci-dessous. Cependant, lorsque l'utilisateur appuie sur le champ de texte, le bouton d'annulation apparaît toujours. De l'aide?
override func viewDidLoad() {
super.viewDidLoad()
resultsTableController = ResultsTableController()
searchController = UISearchController(searchResultsController: resultsTableController)
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.delegate = self
//Hide cancel button - added by me
searchController.searchBar.showsCancelButton = false
...
Je pense qu'il y a trois façons d'y parvenir:
searchController.searchBar.showsCancelButton = false
Sous-classe UISearchBar et substituez les layoutSubviews pour changer cette variable lorsque le système tente de le dessiner.
Enregistrez-vous pour la notification au clavier UIKeyboardWillShowNotification et appliquez le code du point 1.
Bien sûr, vous pouvez toujours implémenter votre barre de recherche.
Pour iOS 8 et UISearchController, utilisez cette méthode de délégué à partir de UISearchControllerDelegate
:
func didPresentSearchController(searchController: UISearchController) {
searchController.searchBar.showsCancelButton = false
}
N'oubliez pas de vous définir en tant que délégué: searchController.delegate = self
Sous-classe simplement UISearchController
& UISearchBar
.
class NoCancelButtonSearchController: UISearchController {
let noCancelButtonSearchBar = NoCancelButtonSearchBar()
override var searchBar: UISearchBar { return noCancelButtonSearchBar }
}
class NoCancelButtonSearchBar: UISearchBar {
override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) { /* void */ }
}
Les sous-classes de projet github suivantes, UISearchBar, sont présentées comme solution 2:
https://github.com/mechaman/CustomSearchControllerSwift
De plus, il sous-classe UISearchController pour permettre de placer la barre de recherche ailleurs que dans l'en-tête tableView!
J'espère que cela t'aides.
C’était la solution la plus simple que je pouvais trouver dans Swift.
Contrôleur de recherche personnalisé:
class CustomSearchController: UISearchController {
var _searchBar: CustomSearchBar
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
self._searchBar = CustomSearchBar()
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
override init(searchResultsController: UIViewController?) {
self._searchBar = CustomSearchBar()
super.init(searchResultsController: searchResultsController)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var searchBar: UISearchBar {
return self._searchBar
}
}
Barre de recherche personnalisée:
class CustomSearchBar: UISearchBar {
override func setShowsCancelButton(showsCancelButton: Bool, animated: Bool) {
// do nothing
}
}
L'élément le plus important de cette opération consistait à ne créer l'objet _searchBar
qu'une seule fois dans init
et à le créer à l'intérieur de la propriété stockée.
Sous-classe simplement votre UISearchController et procédez comme suit:
class CustomSearchController: UISearchController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
searchBar.showsCancelButton = false
}
}
C’était la solution la plus simple que je pouvais trouver pour résoudre le problème du bouton d’annulation clignotant.
TL; DR: Le sous-classement UISearchBar
et la substitution de setShowsCancelButton:
et setShowsCancelButton:animated:
masquent le bouton d'annulation.
Je règle active
sur NO
si la barre de recherche n'est pas le premier répondant (le clavier n'est ni actif ni affiché), puisqu'il s'agit en réalité d'une commande cancel.
Le marquage searchController.searchBar.showsCancelButton = NO
ne semble pas fonctionner dans iOS 8. Je n'ai pas testé iOS 9.
Vide, mais placé ici pour être complet.
@import UIKit;
@interface FJSearchBar : UISearchBar
@end
#import "FJSearchBar.h"
@implementation FJSearchBar
- (void)setShowsCancelButton:(BOOL)showsCancelButton {
// do nothing
}
- (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
// do nothing
}
@end
Voici où vous voulez faire les vrais changements. Je divise la UISearchBarDelegate
dans sa propre catégorie car, à mon humble avis, les catégories rendent les classes plus propres et plus faciles à gérer. Si vous souhaitez conserver le délégué dans l'interface/l'implémentation de la classe principale, n'hésitez pas.
@import UIKit;
@interface FJSearchController : UISearchController
@end
@interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate>
@end
#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
Quelques pièces à noter:
BOOL
comme variables privées au lieu de propriétés, car searchBar
est le premier intervenant. Si ce n'est pas le cas, nous désactivons le contrôleur de recherche car le texte est vide et nous ne cherchons plus. Si vous (vraiment} _ voulez être sûr, vous pouvez également vous assurer que searchText.length == 0
.searchBar:textDidChange:
est appelé avant searchBarShouldBeginEditing:
, raison pour laquelle nous l'avons traité dans cet ordre.[self.searchResultsUpdater updateSearchResultsForSearchController:self];
vers searchBarSearchButtonClicked:
si vous souhaitez que la recherche soit effectuée uniquement lorsque l'utilisateur appuie sur le bouton Search.Utilisez UISearchControllerDelegate.
func willPresentSearchController(_ searchController: UISearchController) {
searchController.searchBar.setValue("", forKey:"_cancelButtonText")
}