Si j'ai bien compris, le comportement par défaut de UISearchController
est le suivant:
SearchResultsController
n'est pas montré jusqu'à ce point.SearchResultsController
est affiché uniquement si la barre de recherche n'est pas vide.Je souhaite afficher SearchResultsController
même lorsque la barre de recherche est vide mais sélectionnée (c'est-à-dire le cas 1 ci-dessus).
En termes simples, au lieu d'atténuer l'arrière-plan, j'aimerais afficher les résultats de la recherche.
Y a-t-il un moyen de faire cela?
Plus de clarification:
Je n'utilise pas UISearchController
pour filtrer les résultats affichés dans la vue sur laquelle elle est affichée, mais quelques autres résultats sans rapport. Ce sera comme ce que fait Facebook sur son "Fil d'actualité". En appuyant sur la barre de recherche, les suggestions de recherche s'affichent initialement, puis, lorsque nous commençons l'édition, les résultats de la recherche ne concernant pas nécessairement les flux d'actualités.
Si votre barre de recherche est active mais ne contient pas de texte, les résultats de la tableView sous-jacente sont affichés. C'est le comportement intégré et la raison pour laquelle searchResultsController est masqué pour cet état.
Pour modifier le comportement lorsque la recherche est active mais ne filtre pas, vous devrez afficher le searchResultsController quand il est normalement toujours masqué.
Il peut y avoir un bon moyen d’y parvenir via <UISearchResultsUpdating>
et updateSearchResultsForSearchController:
. Si vous pouvez le résoudre via le protocole, c'est la voie à suivre.
Si cela ne vous aide pas, vous vous retrouvez avec le piratage du comportement intégré. Je ne le recommanderais pas et je n’aurais pas confiance en lui, et ça va être fragile, mais voici une réponse si vous choisissez cette option:
Assurez-vous que votre tableViewController est conforme à <UISearchControllerDelegate>
et ajoutez
self.searchController.delegate = self;
Implémenter willPresentSearchController:
- (void)willPresentSearchController:(UISearchController *)searchController
{
dispatch_async(dispatch_get_main_queue(), ^{
searchController.searchResultsController.view.hidden = NO;
});
}
Ceci rend la searchResultsController
visible après que sa UISearchController
soit définie sur masqué.
Implémenter didPresentSearchController:
- (void)didPresentSearchController:(UISearchController *)searchController
{
searchController.searchResultsController.view.hidden = NO;
}
Pour une meilleure façon de contourner le comportement intégré, voir la réponse de malhal .
Vous pouvez simplement implémenter le protocole UISearchResultsUpdating
et définir la vue du contrôleur de résultats pour qu'elle s'affiche toujours dans updateSearchResultsForSearchController
:
func updateSearchResultsForSearchController(searchController: UISearchController) {
// Always show the search result controller
searchController.searchResultsController?.view.hidden = false
// Update your search results data and reload data
..
}
Cela fonctionne car la méthode est appelée même lorsque la barre de recherche est activée, sans aucun texte.
J'ai essayé la solution PetahChristian, le résultat de précharge est apparu lorsque nous avons ciblé la barre de recherche pour la première fois, mais lorsque nous saisissons quelque chose, puis l'effacez, les résultats de précharge ne réapparaissent pas.
Je suis venu avec une autre solution. Nous avons seulement besoin d'ajouter un délégué dans SearchResultsController et de l'appeler lorsque notre searchController.searchBar.text est vide. Quelque chose comme ça:
SearchResultsController:
protocol SearchResultsViewControllerDelegate {
func reassureShowingList() -> Void
}
class FullSearchResultsViewController: UIViewController, UISearchResultsUpdating{
var delegate: SearchResultsViewControllerDelegate?
...
func updateSearchResultsForSearchController(searchController: UISearchController) {
let query = searchController.searchBar.text?.trim()
if query == nil || query!.isEmpty {
...
self.delegate?.reassureShowingList()
...
}
...
}
Et dans le contrôleur contient le SearchController, nous ajoutons notre délégué:
self.searchResultsController.delegate = self
func reassureShowingList() {
searchController.searchResultsController!.view.hidden = false
}
Avec des choses difficiles comme celle-ci, je recommande l'approche du marteau-luge! C’est pour détecter quand quelque chose essaie de le cacher et quand il le fait, le remettre en place. Cela peut être fait via KVO (Key Value Observing). Cela fonctionnera dans tous les cas, sans avoir à gérer toutes les subtilités de la barre de recherche. Désolé, le code est compliqué, mais KVO est une API de style ancien, mais mon code suit les recommandations. Dans votre SearchResultsViewController, mettez ceci:
static int kHidden;
@implementation SearchResultsViewController
-(void)viewDidLoad{
[super viewDidLoad];
[self.view addObserver:self
forKeyPath:@"hidden"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:&kHidden];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
// if it was our observation
if(context == &kHidden){
// if the view is hidden then make it visible.
if([[change objectForKey:NSKeyValueChangeNewKey] boolValue]){
self.view.hidden = NO;
}
}
else{
// if necessary, pass the method up the subclass hierarchy.
if([super respondsToSelector:@selector(observeValueForKeyPath:ofObject:change:context:)]){
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}
}
- (void)dealloc
{
[self.view removeObserver:self forKeyPath:@"hidden"];
}
// Here have the rest of your code for the search results table.
@end
Cela fonctionne dans tous les cas, y compris si le texte est effacé.
Enfin, pour éviter que la table ne se décolore en gris puis en blanc lorsque la recherche est activée, utilisez ceci:
self.searchController.dimsBackgroundDuringPresentation = NO;
Swift 3 Version:
Si votre searchResultController
n'est pas nil et que vous utilisez un contrôleur de vue de table séparé pour afficher les résultats de la recherche, vous pouvez le rendre conforme à UISearchResultUpdating
et dans la fonction updateSearchResults
, vous pouvez simplement masquer la vue.
func updateSearchResults(for searchController: UISearchController) {
view.hidden = false
}
Swift 4 Version:
func updateSearchResults(for searchController: UISearchController) {
view.isHidden = false
}
La version 2.3 de Swift de l'approche de @ malhal:
class SearchResultsViewController : UIViewController {
var context = 0
override func viewDidLoad() {
super.viewDidLoad()
// Add observer
view.addObserver(self, forKeyPath: "hidden", options: [ .New, .Old ], context: &context)
}
deinit {
view.removeObserver(self, forKeyPath: "hidden")
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if context == &self.context {
if change?[NSKeyValueChangeNewKey] as? Bool == true {
view.hidden = false
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
}
Je travaille récemment sur UISearchController
. Je souhaite afficher l'historique de recherche dans searchResultsController
lorsque la barre de recherche est vide. Donc, searchResultsController
doit apparaître lorsque UISearchController
est présenté.
J'ai essayé une autre solution pour rendre la searchResultsController
toujours visible en en surchargeant la propriété hidden
dans une vue personnalisée .
par exemple, ma searchResultsController
est une UITableViewController
. Je crée un VisibleTableView en tant que sous-classe de UITableView
, puis je change la classe personnalisée UITableView
de searchResultsController
en VisibleTableView in xib ou en storyboard. De cette façon, ma searchResultsController
ne sera jamais cachée par UISearchController
.
Les bonnes choses ici:
Plus facile à mettre en œuvre que KVO.
Aucun délai pour afficher searchResultsController
. L'inversion de l'indicateur masqué dans la méthode déléguée "updateSearchResults" fonctionne, mais il y a un délai d'affichage de la variable searchResultsController
.
Il ne réinitialise pas le drapeau caché, il n'y a donc pas d'écart/saut entre l'interface cachée et visible.
Exemple de code Swift 3 :
class VisibleTableView: UITableView {
override var isHidden: Bool {
get {
return false
}
set {
// ignoring any settings
}
}
}
Ce qui est caché est la vue du contrôleur de résultats de recherche. Par conséquent, il est suffisant de le révéler à tout moment. Procédez simplement comme suit dans le contrôleur de résultats de recherche:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.view.isHidden = false
}
func updateSearchResults(for searchController: UISearchController) {
self.view.isHidden = false
// ... your other code goes here ...
}
Maintenant, la vue des résultats (c'est-à-dire la vue tableau) est toujours visible, même lorsque le texte de la barre de recherche est vide.
En passant, l'application iOS Mail se comporte comme ceci, et je suppose que c'est ainsi qu'elle est mise en œuvre (sauf si Apple a accès à un paramètre de secret privé UISearchController).
[Testé sous iOS 10 et iOS 11; Je n'ai testé sur aucun système antérieur.]
Je pense que tu te trompes.
SearchResultsController apparaît uniquement lorsqu'il y a des résultats. Ceci est légèrement différent de votre interprétation.
Les résultats sont chargés manuellement en fonction du texte figurant dans la barre de recherche. Vous pouvez donc l'intercepter si la barre de recherche est vide et renvoyer votre propre ensemble de résultats.
Swift 4 version de malhals answer :
class SearchController: UISearchController {
private var viewIsHiddenObserver: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
viewIsHiddenObserver = self.searchResultsController?.view.observe(\.hidden, changeHandler: { [weak self] (view, _) in
guard let searchController = self else {return}
if view.isHidden && searchController.searchBar.isFirstResponder {
view.isHidden = false
}
})
}
}
Veuillez noter le [weak self]
. Sinon, vous introduiriez un cycle de conservation.
J'ai vraiment aimé la réponse de Simon Wang et j'ai travaillé dessus. C'est ce que j'ai fait et cela fonctionne parfaitement:
Je sous-classe UISearchController dans ma classe personnalisée:
class CustomClass: UISearchController {
override var searchResultsController: UIViewController? {
get {
let viewController = super.searchResultsController
viewController?.view.isHidden = false
return viewController
}
set {
// nothing
}
}
}
Assurez-vous également que cela ne figure nulle part dans votre code:
self.resultsSearchController.isActive = true
resultsSearchController est mon contrôleur UISearchController
Si vous ne souhaitez pas assombrir les résultats, définissez la propriété dimsBackgroundDuringPresentation
sur false
.
Cela garantira que le contenu sous-jacent n'est pas estompé lors d'une recherche.
Vous devrez également vous assurer de renvoyer les résultats même lorsque le searchText est vide, sinon une tableview vide sera affichée.
J'ai passé beaucoup de temps avec cela, et finalement la solution que j'ai choisie ressemble à celle de @ malhals, mais la quantité de code est considérablement réduite en utilisant le KVOController de Facebook: https://github.com/facebook/KVOController . Un autre avantage ici est que si votre searchResultsController est un UINavigationController
, vous n'avez pas besoin de le sous-classer pour ajouter du code @ malhal.
// always show searchResultsController, even if text is empty
[self.KVOController observe:self.searchController.searchResultsController.view keyPath:@"hidden" options:NSKeyValueObservingOptionNew block:^(id observer, UIView* view, NSDictionary *change) {
if ([change[NSKeyValueChangeNewKey] boolValue] == YES) {
view.hidden = NO;
}
}];
self.searchController.dimsBackgroundDuringPresentation = NO;
Le plus simple est d’utiliser ReactiveCocoa avec cette extension https://github.com/ColinEberhardt/ReactiveTwitterSearch/blob/master/ReactiveTwitterSearch/Util/UIKitExtensions.Swift
presentViewController(sc, animated: true, completion: {
sc.searchResultsController?.view.rac_hidden.modify({ value -> Bool in
return false
})
} )
où sc est votre UISearchController