web-dev-qa-db-fra.com

UISearchController dans un UIViewController

Je cherche à créer une fonctionnalité similaire à l'application de cartes Apple dans Swift. Est-il possible d'intégrer UISearchController dans une vue normale (c'est-à-dire pas une UITableView)? Si vous en laissez tomber un dans Storyboard, un crash se produira après un clic dans la barre de recherche connectée. Ou y a-t-il un moyen de parvenir à ce résultat avec un UITableView? 

12
UncleAlfonzo

J'ai ajouté une barre de recherche et un contrôleur d'affichage de recherche dans mon contrôleur de vue dans le storyboard. Le contrôleur de vue ne contient que la barre de recherche et le contrôleur d’affichage de la recherche et ne possède pas son propre TableView. Lorsque vous ajoutez la barre de recherche dans votre contrôleur de vue, celui-ci est automatiquement défini comme son délégué.

La barre de recherche et le contrôleur d’affichage de la recherche disposent désormais d’une vue sous forme de tableau qui permet d’afficher les résultats de la recherche lorsque vous cliquez dans la zone et commencez à taper. Cette vue table attend que votre contrôleur de vue fournisse les implémentations des fonctions numberOfRowsInSection et cellForRowAtIndexPath afin que les données soient affichées correctement.

Lorsque vous exécutez votre projet sans ces éléments et que vous appuyez sur dans la barre de recherche, vous obtenez le message d'erreur suivant: -

tableView: numberOfRowsInSection:]: sélecteur non reconnu envoyé à l'instance 0x7fbf63449660 *** Application terminée en raison de l'exception non interceptée 'NSInvalidArgumentException'

Si vous voyez, l'erreur est à la méthode numberOfRowsInSection.

Changez la définition de votre contrôleur de vue de

class ViewController: UIViewController

à

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource

et mettre en œuvre les méthodes requises qui sont: -

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    return UITableViewCell()
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 0
}

Je viens d'ajouter des valeurs de retour par défaut dans les méthodes ci-dessus.

Maintenant, si vous filtrez votre source de données dans vos méthodes searchviewdelegate et configurez votre nombre de lignes et d'informations de cellule dans les deux méthodes ci-dessus correctement, cela devrait fonctionner.

J'espère que cela t'aides!

3
Rajeev Bhatia

Si vous souhaitez utiliser UISearchController avec un non UITableView, voici comment je l'ai fait.

Etant donné que UISearchController n'est pas (encore!) Pris en charge par IB, vous devez not rien y ajouter, comme un UISearchBar.

@interface UIViewControllerSubclass () <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating>

@property (strong, nonatomic) UISearchController *searchController;

@end

@implementation UIViewControllerSubclass

- (void)viewDidLoad
{        
    [super viewDidLoad];
    // Do any custom init from here...

    // Create a UITableViewController to present search results since the actual view controller is not a subclass of UITableViewController in this case
    UITableViewController *searchResultsController = [[UITableViewController alloc] init];

    // Init UISearchController with the search results controller
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];

    // Link the search controller
    self.searchController.searchResultsUpdater = self;

    // This is obviously needed because the search bar will be contained in the navigation bar
    self.searchController.hidesNavigationBarDuringPresentation = NO;

    // Required (?) to set place a search bar in a navigation bar
    self.searchController.searchBar.searchBarStyle = UISearchBarStyleMinimal;

    // This is where you set the search bar in the navigation bar, instead of using table view's header ...
    self.navigationItem.titleView = self.searchController.searchBar;

    // To ensure search results controller is presented in the current view controller
    self.definesPresentationContext = YES;

    // Setting delegates and other stuff
    searchResultsController.tableView.dataSource = self;
    searchResultsController.tableView.delegate = self;
    self.searchController.delegate = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.searchBar.delegate = self;        
}

@end

J'espère que ça suffit pour travailler :-)

Bien entendu, vous devez au moins implémenter les méthodes UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdater.

Prendre plaisir!

37
adauguet

Essayer de comprendre UISearchController moi-même. Le régler sur titleView est pratique, mais sur l’une de mes pages, je devais placer le searchBar tout en haut de la UIViewController:

// Add a normal View into the Storyboard.
// Set constraints:
// - height: 44
// - leading and trailing so that it spans the width of the page
// - vertical position can be anywhere based on your requirements, like near the top
@IBOutlet weak var searchContainerView: UIView!

var searchResultsController = UISearchController()

override func viewDidLoad() {
    // TODO: set the searchResultsController to something
    let controller = UISearchController(searchResultsController: nil)
    // have the search bar span the width of the screen
    controller.searchBar.sizeToFit()
    // add search bar to empty View
    searchContainerView.addSubview(controller.searchBar)
    searchResultsController = controller
}

UPDATE:

Après avoir implémenté UISearchController dans un projet ou deux, je me suis concentré sur l'approche de @ adauguet consistant à intégrer la barre de recherche à la barre de navigation. 

Voici le code dans Swift. Une différence cependant est qu'il ne définit pas le délégué searchBar, car searchResultsUpdater est déjà à l'écoute des modifications de texte.

override func viewDidLoad() {
    super.viewDidLoad()
//        locationManager.delegate = self
//        locationManager.desiredAccuracy = kCLLocationAccuracyBest
//        locationManager.requestWhenInUseAuthorization()
//        locationManager.requestLocation()
    let locationSearchTable = storyboard!.instantiateViewControllerWithIdentifier("LocationSearchTable") as! LocationSearchTable
    resultSearchController = UISearchController(searchResultsController: locationSearchTable)
    resultSearchController?.searchResultsUpdater = locationSearchTable
    let searchBar = resultSearchController!.searchBar
    searchBar.sizeToFit()
    searchBar.placeholder = "Search for places"
    navigationItem.titleView = resultSearchController?.searchBar
    resultSearchController?.hidesNavigationBarDuringPresentation = false
    resultSearchController?.dimsBackgroundDuringPresentation = true
    definesPresentationContext = true
}

De plus, j'ai écrit un article de blog qui crée un projet à partir de rien en utilisant UISearchController pour afficher les résultats de la recherche sur la carte. Il effectue également d'autres tâches que vous pourriez souhaiter dans un projet de carte, comme obtenir l'emplacement de l'utilisateur, déposer des punaises, analyser des repères dans une adresse sur une ligne et créer des boutons de légende vous permettant d'accéder à Apple Maps pour les itinéraires.

http://www.thorntech.com/2016/01/how-to-search-for-location-using-apples-mapkit/

Le blog est assez long, alors voici le dépôt associé à git si vous voulez juste passer au code:

https://github.com/ThornTechPublic/MapKitTutorial

6
Robert Chen

J'ai eu quelques problèmes pour convertir SearchDisplayController dans UIViewController en SearchController dans ViewController car la mise en œuvre de SearchController n'est pas si intuitive. Mais vous pouvez simplement ajouter searcher à partir de SearchController lui-même dans n'importe quelle vue. Vous ne pouvez cependant pas définir de contrainte, car la barre de recherche se déplacerait vers le haut lorsque vous la sélectionnerez (si vous savez comment définir la contrainte sur seachController.searchbar après l'avoir ajoutée à une vue, LET ME KNOW!). Ci-dessous, je partage une liste de contrôle que j'ai trouvée très importante/précieuse lors de la mise en œuvre de SearchController dans ViewController.

// vous pouvez simplement ajouter un chercheur à n'importe quelle vue. Il se déplacerait automatiquement pour montrer la tableView comme par magie. Mais pour cette raison, vous ne pouvez pas définir de contrainte pour la barre de recherche sur la vue d'espace réservé à laquelle vous l'ajoutez. 

[self.searchBarPlaceHolderView addSubview:self.searchController.searchBar];

// vous en avez besoin pour empêcher la barre de recherche de tomber lorsque vous faites la mise au point/la sélectionnez. Vous voudriez définir ceci sur NO si vous ajoutez searchBar au titleview de la barre de navigation.

self.searchController.hidesNavigationBarDuringPresentation = YES;

// assurez-vous de le définir dans votre viewController

self.extendedLayoutIncludesOpaqueBars = true;
self.definesPresentationContext = YES;

// vous devez également donner au contrôleur de recherche un objet tableViewController qui peut être affiché. Vous pouvez également faire self.searchResultsController = [[UITableView alloc] init] pour un test générique.

self.searchResultsController = (UITableViewController *)[ [UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"searchResultsTableViewController"];

self.searchResultsController.tableView.dataSource = self;
self.searchResultsController.tableView.delegate = self;
self.searchResultsController.definesPresentationContext = NO;
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.searchResultsController];
0
coolcool1994