Partager via


Cartes dans Xamarin.iOS

Les cartes sont une fonctionnalité courante dans tous les systèmes d’exploitation mobiles modernes. iOS offre la prise en charge du mappage en mode natif via l’infrastructure map Kit. Avec Map Kit, les applications peuvent facilement ajouter des cartes riches et interactives. Ces cartes peuvent être personnalisées de différentes manières, telles que l’ajout d’annotations pour marquer des emplacements sur une carte et la superposition de graphiques de formes arbitraires. Map Kit a même une prise en charge intégrée pour afficher l’emplacement actuel d’un appareil.

Ajout d’une carte

L’ajout d’une carte à une application s’effectue en ajoutant une MKMapView instance à la hiérarchie d’affichage, comme indiqué ci-dessous :

// map is an MKMapView declared as a class variable
map = new MKMapView (UIScreen.MainScreen.Bounds);
View = map;

MKMapView est une UIView sous-classe qui affiche une carte. L’ajout de la carte à l’aide du code ci-dessus produit une carte interactive :

Exemple de carte

Style de carte

MKMapView prend en charge 3 styles différents de cartes. Pour appliquer un style de carte, définissez simplement la MapType propriété sur une valeur de l’énumération MKMapType :

map.MapType = MKMapType.Standard; //road map
map.MapType = MKMapType.Satellite;
map.MapType = MKMapType.Hybrid;

La capture d’écran suivante montre les différents styles de carte disponibles :

Cette capture d’écran montre les différents styles de carte disponibles

Mouvement panoramique et zoom

MKMapView inclut la prise en charge des fonctionnalités d’interactivité de carte, telles que :

  • Zoom via un mouvement de pincement
  • Mouvement panoramique via un mouvement panoramique

Ces fonctionnalités peuvent être activées ou désactivées en définissant simplement les propriétés et ScrollEnabled les ZoomEnabled propriétés de l’instanceMKMapView, où la valeur par défaut est true pour les deux. Par exemple, pour afficher une carte statique, définissez simplement les propriétés appropriées sur false :

map.ZoomEnabled = false;
map.ScrollEnabled = false;

Emplacement de l'utilisateur

Outre l’interaction utilisateur, MKMapView elle prend également en charge l’affichage de l’emplacement de l’appareil. Il effectue cette opération à l’aide de l’infrastructure d’emplacement principal. Avant de pouvoir accéder à l’emplacement de l’utilisateur, vous devez inviter l’utilisateur. Pour ce faire, créez une instance de CLLocationManager et appelez RequestWhenInUseAuthorization.

CLLocationManager locationManager = new CLLocationManager();
locationManager.RequestWhenInUseAuthorization();
//locationManager.RequestAlwaysAuthorization(); //requests permission for access to location data while running in the background

Notez que dans les versions d’iOS antérieures à la version 8.0, la tentative d’appel RequestWhenInUseAuthorization entraîne une erreur. Veillez à vérifier la version d’iOS avant d’effectuer cet appel si vous envisagez de prendre en charge les versions antérieures à 8.

L’accès à l’emplacement de l’utilisateur nécessite également des modifications apportées à Info.plist. Vous devez définir les clés suivantes relatives aux données d’emplacement :

  • NSLocationWhenInUseUsageDescription : cette clé est utilisée quand vous accédez à l’emplacement d’un utilisateur en train d’interagir avec votre application.
  • NSLocationAlwaysUsageDescription : cette clé est utilisée quand votre application accède à l’emplacement d’un utilisateur en arrière-plan.

Vous pouvez ajouter ces clés en ouvrant Info.plist et en sélectionnant Source en bas de l’éditeur.

Une fois que vous avez mis à jour Info.plist et invité l’utilisateur à accéder à son emplacement, vous pouvez afficher l’emplacement de l’utilisateur sur la carte en définissant la ShowsUserLocation propriété sur true :

map.ShowsUserLocation = true;

Alerte d’accès à l’emplacement autorisé

Annotations

MKMapView prend également en charge l’affichage d’images, appelées annotations, sur une carte. Il peut s’agir d’images personnalisées ou de broches définies par le système de différentes couleurs. Par exemple, la capture d’écran suivante montre une carte avec une épingle et une image personnalisée :

Cette capture d’écran montre une carte avec une épingle et une image personnalisée

Ajout d’une annotation

Une annotation elle-même comporte deux parties :

  • Objet MKAnnotation , qui inclut des données de modèle sur l’annotation, telles que le titre et l’emplacement de l’annotation.
  • MKAnnotationView Qui contient l’image à afficher et éventuellement une légende affichée lorsque l’utilisateur appuie sur l’annotation.

Map Kit utilise le modèle de délégation iOS pour ajouter des annotations à une carte, où la Delegate propriété du MKMapView kit est définie sur une instance d’un MKMapViewDelegate. Il s’agit de l’implémentation de ce délégué responsable du renvoi MKAnnotationView d’une annotation.

Pour ajouter une annotation, l’annotation est d’abord ajoutée en appelant AddAnnotations l’instance MKMapView :

// add an annotation
map.AddAnnotations (new MKPointAnnotation (){
    Title="MyAnnotation",
    Coordinate = new CLLocationCoordinate2D (42.364260, -71.120824)
});

Lorsque l’emplacement de l’annotation devient visible sur la carte, il MKMapView appelle la méthode de GetViewForAnnotation son délégué pour obtenir l’affichage MKAnnotationView .

Par exemple, le code suivant retourne un système fourni MKPinAnnotationView:

string pId = "PinAnnotation";

public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation)
{
    if (annotation is MKUserLocation)
        return null;

    // create pin annotation view
    MKAnnotationView pinView = (MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);

    if (pinView == null)
        pinView = new MKPinAnnotationView (annotation, pId);

    ((MKPinAnnotationView)pinView).PinColor = MKPinAnnotationColor.Red;
    pinView.CanShowCallout = true;

    return pinView;
}

Réutilisation des annotations

Pour économiser de la mémoire, MKMapView permet de regrouper les vues d’annotations à des fins de réutilisation, comme la façon dont les cellules du tableau sont réutilisées. L’obtention d’une vue d’annotation à partir du pool est effectuée avec un appel à DequeueReusableAnnotation:

MKAnnotationView pinView = (MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);

Affichage des légendes

Comme mentionné précédemment, une annotation peut éventuellement afficher une légende. Pour afficher une légende simplement définie CanShowCallout sur true sur le MKAnnotationView. Cela entraîne l’affichage du titre de l’annotation lorsque l’annotation est tapée, comme indiqué :

Titre des annotations affichées

Personnalisation de la légende

La légende peut également être personnalisée pour afficher les vues d’accessoires gauche et droite, comme indiqué ci-dessous :

pinView.RightCalloutAccessoryView = UIButton.FromType (UIButtonType.DetailDisclosure);
pinView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile ("monkey.png"));

Ce code entraîne la légende suivante :

Exemple de légende

Pour gérer l’utilisateur en appuyant sur l’accessoire approprié, implémentez simplement la CalloutAccessoryControlTapped méthode dans :MKMapViewDelegate

public override void CalloutAccessoryControlTapped (MKMapView mapView, MKAnnotationView view, UIControl control)
{
    ...
}

Superpositions

Une autre façon de calquer des graphiques sur une carte consiste à utiliser des superpositions. Les superpositions prennent en charge le tracé de contenu graphique qui s’ajuste à la carte quand celle-ci est zoomée. iOS prend en charge plusieurs types de superpositions, notamment :

  • Polygones : couramment utilisés pour mettre en surbrillance une région sur une carte.
  • Polylines - Souvent vu lors de l’affichage d’un itinéraire.
  • Cercles : utilisé pour mettre en surbrillance une zone circulaire d’une carte.

En outre, des superpositions personnalisées peuvent être créées pour afficher des géométries arbitraires avec du code de dessin précis et personnalisé. Par exemple, le radar météorologique serait un bon candidat pour une superposition personnalisée.

Ajout d’une superposition

Comme pour les annotations, l’ajout d’une superposition implique 2 parties :

  • Création d’un objet de modèle pour la superposition et l’ajout à l’objet MKMapView .
  • Création d’une vue pour la superposition dans le MKMapViewDelegate .

Le modèle de la superposition peut être n’importe quelle MKShape sous-classe. Xamarin.iOS inclut MKShape des sous-classes pour les polygones, les polylignes et les cercles, via les classes et MKCircle les MKPolygonMKPolyline classes respectivement.

Par exemple, le code suivant est utilisé pour ajouter un MKCircle:

var circleOverlay = MKCircle.Circle (mapCenter, 1000);
map.AddOverlay (circleOverlay);

La vue d’une superposition est une MKOverlayView instance retournée par le GetViewForOverlay MKMapViewDelegatefichier . Chacun MKShape a un correspondant MKOverlayView qui sait comment afficher la forme donnée. Pour MKPolygon qu’il y ait MKPolygonView. De même, MKPolyline correspond à MKPolylineView, et pour MKCircle il y a MKCircleView.

Par exemple, le code suivant retourne un MKCircleView pour un MKCircle:

public override MKOverlayView GetViewForOverlay (MKMapView mapView, NSObject overlay)
{
    var circleOverlay = overlay as MKCircle;
    var circleView = new MKCircleView (circleOverlay);
    circleView.FillColor = UIColor.Blue;
    return circleView;
}

Cela affiche un cercle sur la carte, comme indiqué :

Cercle affiché sur la carte

iOS inclut une API de recherche locale avec Map Kit, qui permet de rechercher des points d’intérêt asynchrones dans une région géographique spécifiée.

Pour effectuer une recherche locale, une application doit suivre les étapes suivantes :

  1. Créez l'objet MKLocalSearchRequest .
  2. Créez un MKLocalSearch objet à partir du MKLocalSearchRequest .
  3. Appelez la Start méthode sur l’objet MKLocalSearch .
  4. Récupérez l’objet MKLocalSearchResponse dans un rappel.

L’API de recherche locale elle-même ne fournit aucune interface utilisateur. Il ne nécessite même pas d’utilisation d’une carte. Toutefois, pour utiliser la recherche locale, une application doit fournir un moyen de spécifier une requête de recherche et d’afficher les résultats. En outre, étant donné que les résultats contiennent des données d’emplacement, il est souvent judicieux de les afficher sur une carte.

Ajout d’une interface utilisateur de recherche locale

Une façon d’accepter l’entrée de recherche est avec un UISearchBar, fourni par un UISearchController et affiche les résultats dans une table.

Le code suivant ajoute le UISearchController (qui a une propriété de barre de recherche) dans la ViewDidLoad méthode de MapViewController:

//Creates an instance of a custom View Controller that holds the results
var searchResultsController = new SearchResultsViewController (map);

//Creates a search controller updater
var searchUpdater = new SearchResultsUpdator ();
searchUpdater.UpdateSearchResults += searchResultsController.Search;

//add the search controller
searchController = new UISearchController (searchResultsController) {
                SearchResultsUpdater = searchUpdater
            };

//format the search bar
searchController.SearchBar.SizeToFit ();
searchController.SearchBar.SearchBarStyle = UISearchBarStyle.Minimal;
searchController.SearchBar.Placeholder = "Enter a search query";

//the search bar is contained in the navigation bar, so it should be visible
searchController.HidesNavigationBarDuringPresentation = false;

//Ensure the searchResultsController is presented in the current View Controller
DefinesPresentationContext = true;

//Set the search bar in the navigation bar
NavigationItem.TitleView = searchController.SearchBar;

Notez que vous êtes responsable de l’incorporation de l’objet de barre de recherche dans l’interface utilisateur. Dans cet exemple, nous l’avons affecté à titleView de la barre de navigation, mais si vous n’utilisez pas de contrôleur de navigation dans votre application, vous devrez trouver un autre emplacement pour l’afficher.

Dans cet extrait de code, nous avons créé un autre contrôleur d’affichage personnalisé , searchResultsController qui affiche les résultats de la recherche, puis nous avons utilisé cet objet pour créer notre objet de contrôleur de recherche. Nous avons également créé un nouveau générateur de mise à jour de recherche, qui devient actif lorsque l’utilisateur interagit avec la barre de recherche. Il reçoit des notifications sur les recherches avec chaque séquence de touches et est responsable de la mise à jour de l’interface utilisateur. Nous allons examiner comment implémenter les searchResultsController deux et les searchResultsUpdater versions ultérieures de ce guide.

Cela entraîne l’affichage d’une barre de recherche sur la carte, comme indiqué ci-dessous :

Barre de recherche affichée sur la carte

Affichage des résultats de la recherche

Pour afficher les résultats de la recherche, nous devons créer un contrôleur de vue personnalisé ; normalement un UITableViewController. Comme indiqué ci-dessus, il searchResultsController est passé au constructeur du moment où searchController il est créé. Le code suivant est un exemple de création de ce contrôleur d’affichage personnalisé :

public class SearchResultsViewController : UITableViewController
{
    static readonly string mapItemCellId = "mapItemCellId";
    MKMapView map;

    public List<MKMapItem> MapItems { get; set; }

    public SearchResultsViewController (MKMapView map)
    {
        this.map = map;

        MapItems = new List<MKMapItem> ();
    }

    public override nint RowsInSection (UITableView tableView, nint section)
    {
        return MapItems.Count;
    }

    public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
    {
        var cell = tableView.DequeueReusableCell (mapItemCellId);

        if (cell == null)
            cell = new UITableViewCell ();

        cell.TextLabel.Text = MapItems [indexPath.Row].Name;
        return cell;
    }

    public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
    {
        // add item to map
        CLLocationCoordinate2D coord = MapItems [indexPath.Row].Placemark.Location.Coordinate;
        map.AddAnnotations (new MKPointAnnotation () {
            Title = MapItems [indexPath.Row].Name,
            Coordinate = coord
        });

        map.SetCenterCoordinate (coord, true);

        DismissViewController (false, null);
    }

    public void Search (string forSearchString)
    {
        // create search request
        var searchRequest = new MKLocalSearchRequest ();
        searchRequest.NaturalLanguageQuery = forSearchString;
        searchRequest.Region = new MKCoordinateRegion (map.UserLocation.Coordinate, new MKCoordinateSpan (0.25, 0.25));

        // perform search
        var localSearch = new MKLocalSearch (searchRequest);

        localSearch.Start (delegate (MKLocalSearchResponse response, NSError error) {
            if (response != null && error == null) {
                this.MapItems = response.MapItems.ToList ();
                this.TableView.ReloadData ();
            } else {
                Console.WriteLine ("local search error: {0}", error);
            }
        });

    }
}

Mise à jour des résultats de la recherche

Il SearchResultsUpdater agit en tant que médiateur entre la searchControllerbarre de recherche et les résultats de recherche.

Dans cet exemple, nous devons d’abord créer la méthode de recherche dans le SearchResultsViewController. Pour ce faire, nous devons créer un MKLocalSearch objet et l’utiliser pour émettre une recherche d’un MKLocalSearchRequest, les résultats sont récupérés dans un rappel passé à la Start méthode de l’objet MKLocalSearch . Les résultats sont ensuite retournés dans un MKLocalSearchResponse objet contenant un tableau d’objets MKMapItem :

public void Search (string forSearchString)
{
    // create search request
    var searchRequest = new MKLocalSearchRequest ();
    searchRequest.NaturalLanguageQuery = forSearchString;
    searchRequest.Region = new MKCoordinateRegion (map.UserLocation.Coordinate, new MKCoordinateSpan (0.25, 0.25));

    // perform search
    var localSearch = new MKLocalSearch (searchRequest);

    localSearch.Start (delegate (MKLocalSearchResponse response, NSError error) {
        if (response != null && error == null) {
            this.MapItems = response.MapItems.ToList ();
            this.TableView.ReloadData ();
        } else {
            Console.WriteLine ("local search error: {0}", error);
        }
    });

}

Ensuite, dans notre article MapViewController , nous allons créer une implémentation personnalisée de UISearchResultsUpdating, qui est affectée à la SearchResultsUpdater propriété de notre searchController dans la section Ajout d’une interface utilisateur de recherche locale :

public class SearchResultsUpdator : UISearchResultsUpdating
{
    public event Action<string> UpdateSearchResults = delegate {};

    public override void UpdateSearchResultsForSearchController (UISearchController searchController)
    {
        this.UpdateSearchResults (searchController.SearchBar.Text);
    }
}

L’implémentation ci-dessus ajoute une annotation à la carte lorsqu’un élément est sélectionné dans les résultats, comme indiqué ci-dessous :

Annotation ajoutée à la carte lorsqu’un élément est sélectionné dans les résultats

Important

UISearchController a été implémenté dans iOS 8. Si vous souhaitez prendre en charge les appareils antérieurs à celui-ci, vous devez utiliser UISearchDisplayController.

Résumé

Cet article a examiné l’infrastructure map Kit pour iOS. Tout d’abord, il a examiné la façon dont la MKMapView classe permet l’inclusion de cartes interactives dans une application. Il a ensuite montré comment personnaliser davantage les cartes à l’aide d’annotations et de superpositions. Enfin, elle a examiné les fonctionnalités de recherche locales qui ont été ajoutées au Kit de mappage avec iOS 6.1, montrant comment utiliser des requêtes basées sur des emplacements pour des points d’intérêt et les ajouter à une carte.