Freigeben über


Karten in Xamarin.iOS

Karten sind ein gemeinsames Feature in allen modernen mobilen Betriebssystemen. iOS bietet systemeigene Kartenunterstützung ü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. Hinzufügen von Anmerkungen zum Markieren von Orten auf einer Karte und Überlagerung von Grafiken beliebiger Formen. Das Map Kit bietet sogar integrierte Unterstützung für die Anzeige der aktuellen Position eines Geräts.

Hinzufügen einer Karte

Das Hinzufügen einer Zuordnung zu einer Anwendung erfolgt durch Hinzufügen einer MKMapView Instanz zur Ansichtshierarchie, wie unten dargestellt:

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

Beispielkarte

Kartenformat

MKMapView unterstützt 3 verschiedene Kartenformatvorlagen. Um ein Kartenformat anzuwenden, legen Sie die MapType Eigenschaft einfach 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 Kartenformatvorlagen:

Dieser Screenshot zeigt die verschiedenen verfügbaren Kartenformatvorlagen.

Verschieben und Zoomen

MKMapView enthält Unterstützung für Interaktivitätsfeatures für Karten, z. B.:

  • Zoomen über eine Zusammendrückbewegung
  • Verschieben über eine Verschiebungsgeste

Diese Features können aktiviert oder deaktiviert werden, indem sie einfach die ZoomEnabled Eigenschaften ScrollEnabled und Eigenschaften der MKMapView Instanz festlegen, wobei der Standardwert für beide zutrifft. Wenn Sie beispielsweise eine statische Karte anzeigen möchten, legen Sie einfach die entsprechenden Eigenschaften auf "false" fest:

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

Benutzerstandort

Zusätzlich zur Benutzerinteraktion MKMapView bietet es auch integrierte Unterstützung für die Anzeige der Position 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 auffordern. Erstellen Sie dazu eine Instanz von CLLocationManager und rufen Sie sie auf RequestWhenInUseAuthorization.

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

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

Für den Zugriff auf den Standort des Benutzers sind auch Änderungen an Info.plist erforderlich. 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 aufgefordert haben, auf seinen Standort zuzugreifen, können Sie die Position des Benutzers auf der Karte anzeigen, indem Sie die ShowsUserLocation Eigenschaft auf "true" festlegen:

map.ShowsUserLocation = true;

Die Warnung für den Zugriff auf den Standort zulassen

Anmerkungen

MKMapView unterstützt auch das Anzeigen von Bildern, die als Anmerkungen bezeichnet werden, auf einer Karte. Hierbei kann es sich entweder um benutzerdefinierte Bilder oder systemdefinierte Pins verschiedener Farben handelt. Der folgende Screenshot zeigt beispielsweise eine Karte mit einem Pin und einem benutzerdefinierten Bild:

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

Hinzufügen einer Anmerkung

Eine Anmerkung selbst hat zwei Teile:

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

Map Kit verwendet das iOS-Delegierungsmuster, um anmerkungen zu einer Karte hinzuzufügen, wobei die Delegate Eigenschaft des MKMapView Objekts auf eine Instanz einer MKMapViewDelegate. Es handelt sich um die Implementierung dieser Stellvertretung, die für die MKAnnotationView Rückgabe einer Anmerkung verantwortlich ist.

Um eine Anmerkung hinzuzufügen, wird zuerst die Anmerkung durch Aufrufen AddAnnotations der MKMapView Instanz hinzugefügt:

// 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 Stellvertretungsmethode GetViewForAnnotation auf, um die MKAnnotationView Anzeige zu erhalten.

Der folgende Code gibt z. B. einen vom System bereitgestellten MKPinAnnotationViewCode zurü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;
}

Erneutes Wiederverwenden von Anmerkungen

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

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

Anzeigen von Beschriftungen

Wie bereits erwähnt, kann eine Anmerkung optional eine Legende anzeigen. So zeigen Sie eine Legende einfach CanShowCallout auf "true" auf der MKAnnotationView. Dies führt dazu, dass der Titel der Anmerkung angezeigt wird, wenn auf die Anmerkung getippt wird, wie gezeigt:

Der Titel der Anmerkungen, die angezeigt werden

Anpassen der Legende

Die Legende kann auch so angepasst werden, dass links- und rechte Zubehöransichten angezeigt werden, wie unten dargestellt:

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

Dieser Code führt zu der folgenden Legende:

Ein Beispiel für eine Legende

Um den Benutzer auf das richtige Zubehör zu tippen, implementieren Sie einfach die CalloutAccessoryControlTapped Methode in der: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 Überlagerungen. Überlagerungen unterstützen das Zeichnen grafischer Inhalte, die beim Zoomen mit der Karte skaliert werden. iOS bietet Unterstützung für verschiedene Arten von Überlagerungen, darunter:

  • Polygone – Häufig verwendet, um einige Regionen 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 präzisem, angepassten Zeichnungscode anzuzeigen. Beispielsweise wäre Wetterradar ein guter Kandidat für eine benutzerdefinierte Überlagerung.

Hinzufügen einer Überlagerung

Ähnlich wie Anmerkungen umfasst das Hinzufügen einer Überlagerung zwei Teile:

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

Das Modell für die Überlagerung kann eine beliebige MKShape Unterklasse sein. Xamarin.iOS umfasst MKShape Unterklassen für Polygone, Polylinien und Kreise über die MKPolygonMKPolyline klassen bzwMKCircle. klassen.

Der folgende Code wird z. B. zum Hinzufügen eines MKCircle:

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

Die Ansicht für eine Überlagerung ist eine MKOverlayView Instanz, die von der in der GetViewForOverlay MKMapViewDelegate. Jeder MKShape verfügt über ein entsprechendes MKOverlayView Element, das weiß, wie die angegebene Form angezeigt wird. Dafür MKPolygon gibt MKPolygonViewes . MKPolyline Entsprechend entspricht MKPolylineViewes , und für MKCircle es gibt MKCircleView.

Der folgende Code gibt z. B. einen MKCircleView Wert für ein 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;
}

Dadurch wird wie gezeigt ein Kreis auf der Karte angezeigt:

Ein Kreis, der auf der Karte angezeigt wird

iOS enthält eine lokale Such-API mit Map Kit, die asynchrone Suchen nach interessanten Orten in einer bestimmten 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 dem 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 erforderlich, dass eine Karte verwendet wird. Um die lokale Suche praktisch nutzen zu können, muss eine Anwendung jedoch eine Möglichkeit zum Angeben einer Suchabfrage und zum Anzeigen von Ergebnissen bereitstellen. Da die Ergebnisse Standortdaten enthalten, ist es häufig sinnvoll, sie auf einer Karte anzuzeigen.

Hinzufügen einer lokalen Such-UI

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

Der folgende Code fügt die UISearchController (mit einer Suchleisteneigenschaft) in der ViewDidLoad Methode von 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;

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, an dem sie angezeigt werden kann.

In diesem Codeausschnitt haben wir einen weiteren benutzerdefinierten Ansichtscontroller erstellt, searchResultsController der die Suchergebnisse anzeigt und dann dieses Objekt zum Erstellen unseres Suchcontrollerobjekts verwendet hat. Außerdem wurde ein neuer Suchupdater erstellt, der aktiv wird, wenn der Benutzer mit der Suchleiste interagiert. Es empfängt Benachrichtigungen über Suchvorgänge mit jedem Tastenanschlag und ist für die Aktualisierung der Benutzeroberfläche verantwortlich. Wir werden uns ansehen, wie Sie sowohl das searchResultsController als auch das searchResultsUpdater spätere In diesem Handbuch implementieren.

Dies führt zu einer Suchleiste, die wie unten dargestellt über der Karte angezeigt wird:

Eine Suchleiste, die über der Karte angezeigt wird

Anzeigen der Suchergebnisse

Um Suchergebnisse anzuzeigen, müssen wir einen benutzerdefinierten Ansichtscontroller erstellen. normalerweise ein UITableViewController. Wie oben gezeigt, wird der searchResultsController Konstruktor des searchController Zeitpunkts der Erstellung an den Konstruktor übergeben. Der folgende Code ist ein Beispiel für das Erstellen 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

Der SearchResultsUpdater Dient als Vermittler zwischen der searchControllerSuchleiste und den Suchergebnissen.

In diesem Beispiel müssen wir zuerst die Suchmethode in der SearchResultsViewController. Dazu müssen wir ein MKLocalSearch Objekt erstellen und verwenden, um eine Suche nach einem MKLocalSearchRequestObjekt ausstellen zu können, werden die Ergebnisse 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 unserem MapViewController Abschnitt eine benutzerdefinierte Implementierung von UISearchResultsUpdating, die der SearchResultsUpdater Eigenschaft unserer 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 Karte eine Anmerkung hinzu, wenn ein Element aus den Ergebnissen ausgewählt wird, wie unten dargestellt:

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 Geräte früher unterstützen möchten, müssen Sie diese verwenden UISearchDisplayController.

Zusammenfassung

In diesem Artikel wurde das Map Kit-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 gezeigt, 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, und zeigt, wie Standortbasierte Abfragen für interessante Orte verwendet und zu einer Karte hinzugefügt werden.