Karten in Xamarin.iOS

Karten sind ein gängiges Feature in allen modernen mobilen Betriebssystemen. iOS bietet nativ Unterstützung für die Zuordnung über das Map Kit-Framework. Mit Map Kit können Anwendungen problemlos umfangreiche, interaktive Karten hinzufügen. Diese Karten können auf unterschiedliche Weise angepasst werden, z. B. durch Hinzufügen von Anmerkungen zum Markieren von Positionen auf einer Karte und Überlagern von Grafiken beliebiger Formen. Map Kit verfügt sogar über integrierte Unterstützung zum Anzeigen des aktuellen Standorts eines Geräts.

Hinzufügen einer Karte

Das Hinzufügen einer Zuordnung zu einer Anwendung erfolgt durch Hinzufügen eines MKMapView instance zur Ansichtshierarchie, wie unten gezeigt:

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

MKMapView ist eine UIView Unterklasse, die eine Karte anzeigt. Durch einfaches Hinzufügen der Karte mithilfe des obigen Codes wird eine interaktive Karte erzeugt:

Beispielzuordnung

Kartenformat

MKMapView unterstützt 3 verschiedene Kartenstile. Um eine Zuordnungsart anzuwenden, legen Sie einfach die MapType Eigenschaft auf einen Wert aus der MKMapType Enumeration fest:

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

Der folgende Screenshot zeigt die verschiedenen verfügbaren Kartenstile:

Dieser Screenshot zeigt die verschiedenen verfügbaren Kartenstile.

Schwenken und Zoomen

MKMapView umfasst Unterstützung für Karteninteraktivitätsfeatures, z. B.:

  • Zoomen über eine Pinch-Geste
  • Schwenken über eine Schwenkbewegung

Diese Features können aktiviert oder deaktiviert werden, indem Sie einfach die ZoomEnabled Eigenschaften und ScrollEnabled der MKMapView instance festlegen, wobei der Standardwert für beide true ist. Um beispielsweise eine statische Zuordnung anzuzeigen, legen Sie einfach die entsprechenden Eigenschaften auf false fest:

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

Benutzerstandort

Zusätzlich zur Benutzerinteraktion MKMapView bietet auch integrierte Unterstützung für die Anzeige des Standorts des Geräts. Dazu wird das Core Location-Framework verwendet. Bevor Sie auf den Standort des Benutzers zugreifen können, müssen Sie den Benutzer dazu auffordern. Erstellen Sie hierzu eine instance vonCLLocationManager, und rufen Sie aufRequestWhenInUseAuthorization.

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

Beachten Sie, dass in iOS-Versionen vor 8.0 der Versuch, einen Aufruf zu tätigen RequestWhenInUseAuthorization , zu einem Fehler führt. Überprüfen Sie unbedingt die Version von iOS, bevor Sie diesen Anruf tätigen, wenn Sie Versionen vor 8 unterstützen möchten.

Der Zugriff auf den Standort des Benutzers erfordert auch Änderungen an Info.plist. Die folgenden Schlüssel, die mit den Standortdaten zusammenhängen, sollten festgelegt werden:

  • NSLocationWhenInUseUsageDescription: Für den Zugriff auf den Standort des Benutzers während dieser mit Ihrer App interagiert.
  • NSLocationAlwaysUsageDescription: Für den Zugriff Ihrer App auf den Standort des Benutzers aus dem Hintergrund.

Sie können diese Schlüssel hinzufügen, indem Sie Info.plist öffnen und unten im Editor Quelle auswählen.

Nachdem Sie Info.plist aktualisiert und den Benutzer zur Berechtigung für den Zugriff auf seinen Standort aufgefordert haben, können Sie den Standort des Benutzers auf der Karte anzeigen, indem Sie die ShowsUserLocation Eigenschaft auf true festlegen:

map.ShowsUserLocation = true;

Warnung

Anmerkungen

MKMapView unterstützt auch das Anzeigen von Bildern, die als Anmerkungen bezeichnet werden, auf einer Karte. Dies können benutzerdefinierte Bilder oder systemdefinierte Pins in verschiedenen Farben sein. Der folgende Screenshot zeigt beispielsweise eine Karte mit einem Pin und einem benutzerdefinierten Bild:

Dieser Screenshot zeigt eine Karte mit einer Pin und einem benutzerdefinierten Bild.

Hinzufügen einer Anmerkung

Eine Anmerkung selbst umfasst zwei Teile:

  • Das MKAnnotation -Objekt, das Modelldaten zur Anmerkung enthält, z. B. Titel und Position der Anmerkung.
  • Der MKAnnotationView , der das anzuzeigende Bild und optional eine Legende enthält, die angezeigt wird, wenn der Benutzer auf die Anmerkung tippt.

Map Kit verwendet das iOS-Delegierungsmuster zum Hinzufügen von Anmerkungen zu einer Karte, wobei die Delegate Eigenschaft von MKMapView auf eine instance von MKMapViewDelegatefestgelegt ist. Es ist die Implementierung dieses Delegaten, die für die Rückgabe von für MKAnnotationView eine Anmerkung verantwortlich ist.

Um eine Anmerkung hinzuzufügen, wird zuerst die Anmerkung hinzugefügt, indem sie auf der MKMapView instance aufruftAddAnnotations:

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

Wenn die Position der Anmerkung auf der Karte sichtbar wird, ruft die MKMapView -Methode ihres GetViewForAnnotation Delegaten auf, um die MKAnnotationView anzuzeigende zu erhalten.

Der folgende Code gibt beispielsweise eine vom System bereitgestellte MKPinAnnotationViewzurück:

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

Wiederverwenden von Anmerkungen

Um Arbeitsspeicher zu sparen, MKMapView können Anmerkungsansichten zur Wiederverwendung in einem Pool zusammengefasst werden, ähnlich wie die Wiederverwendung von Tabellenzellen. Das Abrufen einer Anmerkungsansicht aus dem Pool erfolgt mit einem Aufruf von DequeueReusableAnnotation:

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

Legenden anzeigen

Wie bereits erwähnt, kann eine Anmerkung optional eine Beschriftung anzeigen. Um eine Legende anzuzeigen, legen Sie CanShowCallout einfach auf true für fest MKAnnotationView. Dies führt dazu, dass der Titel der Anmerkung angezeigt wird, wenn auf die Anmerkung getippt wird, wie gezeigt:

Der angezeigte Anmerkungstitel

Anpassen der Legende

Die Legende kann auch so angepasst werden, dass linke und rechte Zubehöransichten angezeigt werden, wie unten gezeigt:

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

Dieser Code führt zu folgender Beschriftung:

Beispielausschrift

Um den Benutzer beim Tippen auf das richtige Zubehör zu behandeln, implementieren Sie einfach die CalloutAccessoryControlTapped -Methode in :MKMapViewDelegate

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

Überlagerungen

Eine weitere Möglichkeit zum Layern von Grafiken auf einer Karte ist die Verwendung von Overlays. Überlagerungen unterstützen das Zeichnen grafischer Inhalte, die beim Zoomen mit der Karte skaliert werden. iOS bietet Unterstützung für verschiedene Arten von Overlays, einschließlich:

  • Polygone: Wird häufig verwendet, um eine Region auf einer Karte hervorzuheben.
  • Polylinien : Häufig beim Anzeigen einer Route zu sehen.
  • Kreise: Wird verwendet, um einen kreisförmigen Bereich einer Karte hervorzuheben.

Darüber hinaus können benutzerdefinierte Überlagerungen erstellt werden, um beliebige Geometrien mit granularem, angepasstem Zeichnungscode anzuzeigen. Wetterradar wäre beispielsweise ein guter Kandidat für ein benutzerdefiniertes Overlay.

Hinzufügen eines Overlays

Ähnlich wie bei Anmerkungen umfasst das Hinzufügen eines Overlays zwei Teile:

  • Erstellen eines Modellobjekts für die Überlagerung und Hinzufügen zu MKMapView .
  • Erstellen einer Ansicht für die Überlagerung in .MKMapViewDelegate

Das Modell für die Überlagerung kann eine beliebige MKShape Unterklasse sein. Xamarin.iOS enthält MKShape Unterklassen für Polygone, Polylinien und Kreise über die MKPolygon- MKPolyline und MKCircle -Klassen.

Beispielsweise wird der folgende Code verwendet, um einen MKCirclehinzuzufügen:

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

Die Ansicht für eine Überlagerung ist eine MKOverlayView instance, die GetViewForOverlay von zurückgegeben wird.MKMapViewDelegate Jede MKShape verfügt über eine entsprechende MKOverlayView , die weiß, wie die angegebene Form angezeigt werden kann. Für MKPolygon gibt MKPolygonViewes . MKPolyline Entspricht in ähnlicher Weise , MKPolylineViewund für MKCircle gibt MKCircleViewes .

Der folgende Code gibt z. B. ein MKCircleView für ein MKCirclezurück:

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

Dadurch wird ein Kreis auf der Karte wie folgt angezeigt:

Ein Kreis, der auf der Karte angezeigt wird

iOS enthält eine lokale Such-API mit Map Kit, die asynchrone Suche nach Sehenswürdigkeiten in einer angegebenen geografischen Region ermöglicht.

Um eine lokale Suche auszuführen, muss eine Anwendung die folgenden Schritte ausführen:

  1. Erstellen Sie ein MKLocalSearchRequest -Objekt.
  2. Erstellen Sie ein MKLocalSearch -Objekt aus .MKLocalSearchRequest
  3. Rufen Sie die Start -Methode für das MKLocalSearch -Objekt auf.
  4. Rufen Sie das MKLocalSearchResponse Objekt in einem Rückruf ab.

Die lokale Such-API selbst stellt keine Benutzeroberfläche bereit. Es ist nicht einmal eine Karte erforderlich, um verwendet zu werden. Um jedoch die lokale Suche praktisch nutzen zu können, muss eine Anwendung eine Möglichkeit bieten, eine Suchabfrage anzugeben und Ergebnisse anzuzeigen. Da die Ergebnisse außerdem Standortdaten enthalten, ist es häufig sinnvoll, sie auf einer Karte anzuzeigen.

Hinzufügen einer Benutzeroberfläche für die lokale Suche

Eine Möglichkeit zum Akzeptieren von Sucheingaben ist eine UISearchBar, die von bereitgestellt UISearchController wird und Ergebnisse in einer Tabelle anzeigt.

Der folgende Code fügt ( UISearchController mit einer Suchleisteneigenschaft) in der ViewDidLoad -Methode von MapViewControllerhinzu:

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

Beachten Sie, dass Sie für die Einbindung des Suchleistenobjekts in die Benutzeroberfläche verantwortlich sind. In diesem Beispiel haben wir sie der TitleView der Navigationsleiste zugewiesen, aber wenn Sie keinen Navigationscontroller in Ihrer Anwendung verwenden, müssen Sie einen anderen Ort finden, um ihn anzuzeigen.

In diesem Codeausschnitt haben wir einen weiteren benutzerdefinierten Ansichtscontroller erstellt , searchResultsController der die Suchergebnisse anzeigt, und dann haben wir dieses Objekt verwendet, um unser Suchcontrollerobjekt zu erstellen. Außerdem haben wir einen neuen Suchupdater erstellt, der aktiv wird, wenn der Benutzer mit der Suchleiste interagiert. Es empfängt Benachrichtigungen zu Suchvorgängen mit jeder Tastatureingabe und ist für die Aktualisierung der Benutzeroberfläche verantwortlich. Wir sehen uns an, wie sie sowohl als auch searchResultsControllersearchResultsUpdater später in diesem Handbuch implementieren.

Dies führt dazu, dass eine Suchleiste über der Karte angezeigt wird, wie unten gezeigt:

Eine Suchleiste, die über der Karte angezeigt wird

Anzeigen der Suchergebnisse

Zum Anzeigen von Suchergebnissen müssen wir einen benutzerdefinierten Ansichtscontroller erstellen. normalerweise ein UITableViewController. Wie oben gezeigt, wird der searchResultsController beim Erstellen an den Konstruktor von searchController übergeben. Der folgende Code ist ein Beispiel für die Erstellung dieses benutzerdefinierten Ansichtscontrollers:

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);
            }
        });

    }
}

Aktualisieren der Suchergebnisse

fungiert SearchResultsUpdater als Vermittler zwischen der searchControllerSuchleiste und den Suchergebnissen.

In diesem Beispiel müssen wir zuerst die Suchmethode in der SearchResultsViewControllererstellen. Dazu müssen wir ein MKLocalSearch -Objekt erstellen und es verwenden, um eine Suche nach auszugeben MKLocalSearchRequest, die Ergebnisse werden in einem Rückruf abgerufen, der an die Start -Methode des MKLocalSearch -Objekts übergeben wird. Die Ergebnisse werden dann in einem MKLocalSearchResponse -Objekt zurückgegeben, das ein Array von MKMapItem -Objekten enthält:

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);
        }
    });

}

Anschließend erstellen wir in unserer MapViewController eine benutzerdefinierte Implementierung von UISearchResultsUpdating, die der SearchResultsUpdater -Eigenschaft von searchController im Abschnitt Hinzufügen einer lokalen Suchbenutzeroberfläche zugewiesen ist:

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

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

Die obige Implementierung fügt der Zuordnung eine Anmerkung hinzu, wenn ein Element aus den Ergebnissen ausgewählt wird, wie unten gezeigt:

Eine Anmerkung, die der Karte hinzugefügt wird, wenn ein Element aus den Ergebnissen ausgewählt wird

Wichtig

UISearchController wurde in iOS 8 implementiert. Wenn Sie frühere Geräte unterstützen möchten, müssen Sie verwenden UISearchDisplayController.

Zusammenfassung

In diesem Artikel wurde das MapKit-Framework für iOS untersucht. Zunächst wurde untersucht, wie die MKMapView -Klasse die Aufnahme interaktiver Karten in eine Anwendung ermöglicht. Anschließend wurde veranschaulicht, wie Karten mithilfe von Anmerkungen und Überlagerungen weiter angepasst werden. Schließlich wurden die lokalen Suchfunktionen untersucht, die dem Map Kit mit iOS 6.1 hinzugefügt wurden. Dabei wurde gezeigt, wie standortbasierte Abfragen für Points of Interest verwendet und zu einer Karte hinzugefügt werden.