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:
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:
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;
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:
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 MKPinAnnotationView
Code 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:
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:
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 MKPolygon
MKPolyline
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 MKPolygonView
es . MKPolyline
Entsprechend entspricht MKPolylineView
es , 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:
Lokale Suche
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:
- Erstellen Sie ein
MKLocalSearchRequest
-Objekt. - Erstellen Sie ein
MKLocalSearch
Objekt aus demMKLocalSearchRequest
. - Rufen Sie die
Start
Methode für dasMKLocalSearch
Objekt auf. - 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:
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 searchController
Suchleiste 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 MKLocalSearchRequest
Objekt 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:
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.