wake-up-neo.com

UISearchController: Ergebnisse anzeigen, auch wenn die Suchleiste leer ist

Soweit ich weiß, ist das Standardverhalten von UISearchController:

  1. In der Suchleiste wird der Hintergrund abgeblendet und die Schaltfläche "Abbrechen" wird angezeigt. SearchResultsController wird bis zu diesem Punkt nicht angezeigt.
  2. SearchResultsController wird nur angezeigt, wenn die Suchleiste nicht leer ist.

Ich möchte SearchResultsController anzeigen, auch wenn die Suchleiste leer ist, aber ausgewählt ist (d. H. Fall 1 oben).

Einfach gesagt, anstelle von Hintergrunddimmen möchte ich Suchergebnisse anzeigen.

Gibt es einen Weg, dies zu tun?

Weitere Klarstellung:

Ich verwende nicht UISearchController, um Ergebnisse zu filtern, die in der Ansicht gezeigt werden, in der sie angezeigt wird, sondern einige andere nicht zusammenhängende Ergebnisse. Es wird so sein, wie Facebook es in seinem 'News Feed' tut. Durch Tippen auf die Suchleiste werden zunächst Suchvorschläge angezeigt. Wenn Sie mit der Bearbeitung beginnen, werden Suchergebnisse angezeigt, die möglicherweise nicht mit dem Newsfeed zusammenhängen. 

30
optimus

Wenn Ihre Suchleiste aktiv ist, aber keinen Text enthält, werden die zugrunde liegenden tableView-Ergebnisse angezeigt. Das ist das integrierte Verhalten und der Grund, warum searchResultsController für diesen Status ausgeblendet ist.

Um das Verhalten zu ändern, wenn die Suche aktiv ist, aber nicht gefiltert wird, müssen Sie den searchResultsController anzeigen, wenn er normalerweise noch ausgeblendet ist.

Es gibt möglicherweise eine gute Möglichkeit, dies über <UISearchResultsUpdating> und updateSearchResultsForSearchController: zu erreichen. Wenn Sie es über das Protokoll lösen können, ist dies der bevorzugte Weg.

Wenn das nicht hilft, hacken Sie das integrierte Verhalten ab. Ich würde es nicht empfehlen oder sich darauf verlassen, und es wird zerbrechlich sein, aber hier ist eine Antwort, wenn Sie diese Option wählen:

  1. Stellen Sie sicher, dass Ihr tableViewController mit <UISearchControllerDelegate> übereinstimmt, und fügen Sie hinzu

    self.searchController.delegate = self;

  2. willPresentSearchController: implementieren

    - (void)willPresentSearchController:(UISearchController *)searchController
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            searchController.searchResultsController.view.hidden = NO;
        });
    }
    

    Dies macht die searchResultsController sichtbar, nachdem ihre UISearchController auf hidden gesetzt ist.

  3. didPresentSearchController: implementieren

    - (void)didPresentSearchController:(UISearchController *)searchController
    {
        searchController.searchResultsController.view.hidden = NO;
    }
    

Eine bessere Möglichkeit, das eingebaute Verhalten zu umgehen, finden Sie unter Malhals Antwort .

30
user4151918

Sie können einfach das Protokoll UISearchResultsUpdating implementieren und die Ergebniscontrolleransicht so einstellen, dass sie immer in updateSearchResultsForSearchController angezeigt wird:

 func updateSearchResultsForSearchController(searchController: UISearchController) {

   // Always show the search result controller
   searchController.searchResultsController?.view.hidden = false

   // Update your search results data and reload data
   ..
}

Dies funktioniert, weil die Methode auch bei aktivierter Suchleiste ohne Text aufgerufen wird.

31
Ken Toh

Ich habe die Lösung von PetahChristian ausprobiert. Das Vorladeergebnis wurde angezeigt, als wir die Suchleiste zum ersten Mal fokussierten. Wenn wir jedoch etwas eingeben und es löschen, werden die Vorladeergebnisse nicht erneut angezeigt.

Ich habe eine andere Lösung gefunden. Wir müssen nur einen Delegaten in SearchResultsController hinzufügen und ihn aufrufen, wenn searchController.searchBar.text leer ist. Etwas wie das:

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()
        ...
    }
    ...
}

Und in der Steuerung befindet sich der SearchController, wir fügen unseren Delegierten hinzu:

self.searchResultsController.delegate = self
func reassureShowingList() {
    searchController.searchResultsController!.view.hidden = false
}
13
mashix

Bei so kniffligen Dingen empfehle ich den Vorschlaghammer! Das heißt, wenn etwas versucht, es versteckt zu machen, und wenn ja, ändern Sie es wieder. Dies kann über KVO (Key Value Observing) erfolgen. Dies funktioniert auf jeden Fall, ohne sich mit den Feinheiten der Suchleiste befassen zu müssen. Sorry, der Code ist kompliziert, aber KVO ist eine ältere API, aber mein Code folgt der empfohlenen Vorgehensweise. Fügen Sie in Ihren SearchResultsViewController Folgendes ein:

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

Dies funktioniert in allen Fällen, auch wenn der Text gelöscht wird.

Um zu verhindern, dass die Tabelle bei Aktivierung der Suche eine hässliche Überblendung nach Grau und dann nach Weiß bewirkt, verwenden Sie Folgendes:

self.searchController.dimsBackgroundDuringPresentation = NO;
11
malhal

Swift 3 Version:

Wenn Ihre searchResultController nicht gleich null ist und Sie einen separaten Tabellensichtcontroller verwenden, um die Suchergebnisse anzuzeigen, können Sie den Tabellensichtcontroller mit UISearchResultUpdating und der Funktion updateSearchResults konformisieren.

func updateSearchResults(for searchController: UISearchController) {
    view.hidden = false
}

Swift 4 Version:

func updateSearchResults(for searchController: UISearchController) {
    view.isHidden = false
}
5
Yafi

Die Swift 2.3-Version von @ Malhals Ansatz:

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)
        }
    }
}
3
Niels

Ich arbeite kürzlich an UISearchController. Ich möchte den Suchverlauf in searchResultsController anzeigen, wenn die Suchleiste leer ist. Daher muss searchResultsController angezeigt werden, wenn UISearchController präsentiert wird.

Ich habe eine andere Lösung ausprobiert, um searchResultsController immer sichtbar zu machen, indem die hidden-Eigenschaft in einer benutzerdefinierten Ansicht überschrieben wird.

mein searchResultsController ist beispielsweise ein UITableViewController. Ich erstelle eine VisibleTableView als Unterklasse von UITableView und ändere dann die benutzerdefinierte UITableView-Klasse von searchResultsController in VisibleTableView in xib oder im Storyboard. Auf diese Weise wird mein searchResultsController niemals durch UISearchController ausgeblendet.

Die guten Dinge hier:

  1. Einfacher zu implementieren als KVO.

  2. Keine Verzögerung, um searchResultsController anzuzeigen. Das Ausblenden des ausgeblendeten Flags in der Delegatenmethode "updateSearchResults" funktioniert, aber die Anzeige der searchResultsController verzögert sich.

  3. Die verborgene Flagge wird nicht zurückgesetzt, so dass keine Lücke zwischen den verborgenen und sichtbaren UI besteht.

Swift 3 Beispielcode:

class VisibleTableView: UITableView {
override var isHidden: Bool {
    get {
        return false
    }
    set {
        // ignoring any settings
    }
}
}
2
simonwjw

Was verborgen wird, ist die Ansicht des Controller für Suchergebnisse. Daher reicht es aus, es immer wieder einzublenden, wenn es verborgen ist. Gehen Sie im Suchcontroller einfach wie folgt vor:

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 ...
}

Die Ergebnisansicht (d. H. Die Tabellenansicht) ist jetzt immer sichtbar, auch wenn der Text der Suchleiste leer ist.

Die iOS Mail-App verhält sich übrigens so, und ich gehe davon aus, dass sie so implementiert wird (es sei denn, Apple hat Zugriff auf eine geheime private UISearchController-Einstellung).

[Getestet in iOS 10 und iOS 11; Ich habe auf keinem früheren System getestet.]

2
matt

Ich glaube du irrst dich.

SearchResultsController wird nur angezeigt, wenn Ergebnisse vorhanden sind. Dies unterscheidet sich geringfügig von Ihrer Interpretation.

Die Ergebnisse werden manuell basierend auf dem Text in der Suchleiste geladen. So können Sie es abfangen, wenn die Suchleiste leer ist, und Ihre eigenen Ergebnisse zurückgeben.

0
Fogmeister

Swift 4 version von 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
            }
        })

    }

}

Bitte beachten Sie den [weak self]. Andernfalls würden Sie einen Haltezyklus einführen.

0
Lausbert

Ich mochte die Antwort von Simon Wang wirklich und arbeitete mit dieser und das habe ich auch gemacht und es funktioniert perfekt:

Ich subclass den UISearchController in meiner benutzerdefinierten Klasse:

class CustomClass: UISearchController {
  override var searchResultsController: UIViewController? {
    get {
      let viewController = super.searchResultsController
      viewController?.view.isHidden = false
      return viewController
    }
    set {
      // nothing
    }
  }
}

Stellen Sie außerdem sicher, dass Sie dies nirgendwo in Ihrem Code haben:

self.resultsSearchController.isActive = true

resultsSearchController ist mein UISearchController

0
Volhan Salai

Wenn Sie die Ergebnisse nicht dimmen möchten, setzen Sie die dimsBackgroundDuringPresentation-Eigenschaft auf false.

Dadurch wird sichergestellt, dass der zugrunde liegende Inhalt während einer Suche nicht abgeblendet wird.

Sie müssen auch sicherstellen, dass Sie Ergebnisse zurückgeben, auch wenn der searchText leer ist. Andernfalls wird eine leere Tabellenansicht angezeigt.

0

Ich habe viel Zeit damit verbracht, und letztendlich ist die Lösung, mit der ich gegangen bin, wie @ malhals, aber die Menge an Code wird durch die Verwendung von Facebooks KVOController erheblich reduziert: https://github.com/facebook/KVOController . Ein weiterer Vorteil ist, dass, wenn es sich bei searchResultsController um eine UINavigationController handelt, keine Unterklasse erforderlich ist, nur um den Code von @malhal hinzuzufügen.

// 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;
0
skensell

Der einfachste Weg ist die Verwendung von ReactiveCocoa mit dieser Erweiterung 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
            })
        } )

wo ist sc dein UISearchController

0
Roman Barzyczak