iOS8 Impossible de masquer le button d'annulation sur la barre de search dans UISearchController

Mon but est d'empêcher le button d'annulation d'apparaître dans une barre de search dans un UISearchController. J'ai commencé avec la search de table d' Apple avec l'exemple de code UISearchController et j'ai caché le button d'annulation comme vu dans le code ci-dessous. Cependant, lorsque l'user appuie sur le champ de text, le button 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:

  1. Remplacez searchDisplayControllerDidBeginSearch et utilisez le code suivant:

searchController.searchBar.showsCancelButton = false

  1. Sous-class UISearchBar et replace le layoutSubviews pour changer ce var quand le système tente de le dessiner.

  2. Inscrivez-vous à la notification par keyboard UIKeyboardWillShowNotification et appliquez le code au point 1.

Bien sûr, vous pouvez toujours implémenter votre barre de search.

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

Simplement sous-class 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-classs de projet github suivantes UISearchBar qui est présenté comme solution 2:

https://github.com/mechaman/CustomSearchControllerSwift

En plus, il sous-class aussi UISearchController pour permettre de placer la barre de search dans des endroits autres que l'en-tête tableView!

J'espère que cela t'aides.

TL; DR : sous-class UISearchBar et setShowsCancelButton: et setShowsCancelButton:animated: masque le button d'annulation.

SOLUTION

Je mets active à NO si la barre de search n'est pas le premier répondeur (le keyboard n'est pas actif et affiché), puisqu'il s'agit effectivement d'une command d' annulation .

FJSearchBar

searchController.searchBar.showsCancelButton = NO ne semble pas fonctionner dans iOS 8 . Je n'ai pas testé iOS 9 .

FJSearchBar.h

Vide, mais placé ici pour l'exhaustivité.

 @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 les vrais changements. J'ai divisé le UISearchBarDelegate dans sa propre catégorie parce que, à mon UISearchBarDelegate , les catégories rendent les classs plus propres et plus faciles à maintenir. Si vous souhaitez conserver le délégué dans l'interface / l'implémentation principale de la class, vous êtes le bienvenu.

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:(NSSsortingng *)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 parties à noter:

  1. J'ai mis la barre de search et le BOOL comme variables privées au lieu de propriétés parce que
    • Ils sont plus légers que les propriétés privées.
    • Ils n'ont pas besoin d'être vus ou modifiés par le monde extérieur.
  2. Nous vérifions si searchBar est le premier répondeur. Si ce n'est pas le cas, alors nous désactivons le controller de search car le text est vide et nous ne cherchons plus. Si vous voulez vraiment être sûr, vous pouvez également vous assurer que searchText.length == 0 .
  3. searchBar:textDidChange: est invoqué avant searchBarShouldBeginEditing: c'est pourquoi nous l'avons traité dans cet ordre.
  4. Je mets à jour les résultats de search chaque fois que le text change, mais vous pouvez déplacer le [self.searchResultsUpdater updateSearchResultsForSearchController:self]; à searchBarSearchButtonClicked: si vous voulez seulement la search effectuée après que l'user appuie sur le button de search .

C'était la solution la plus simple que je pouvais find dans Swift.

Contrôleur de search personnalisé:

 class CustomSearchController: UISearchController { var _searchBar: CustomSearchBar override init(nibName nibNameOrNil: Ssortingng?, 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 search personnalisée:

 class CustomSearchBar: UISearchBar { override func setShowsCancelButton(showsCancelButton: Bool, animated: Bool) { // do nothing } } 

La partie la plus importante de ceci était de créer seulement l'object _searchBar une fois dans init rapport à la création à l'intérieur de la propriété stockée.

Utilisez UISearchControllerDelegate.

 func willPresentSearchController(_ searchController: UISearchController) { searchController.searchBar.setValue("", forKey:"_cancelButtonText") } 

Juste sous-classr 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 j'ai pu find pour résoudre le problème du button d'annulation clignotant.