Mappe in Xamarin.iOS
Le mappe sono una funzionalità comune in tutti i moderni sistemi operativi mobili. iOS offre il supporto per il mapping in modo nativo tramite il framework Map Kit. Con Map Kit, le applicazioni possono aggiungere facilmente mappe interattive e ricche. Queste mappe possono essere personalizzate in diversi modi, ad esempio aggiungendo annotazioni per contrassegnare le posizioni su una mappa e sovrapponendo grafica di forme arbitrarie. Map Kit include anche il supporto predefinito per visualizzare la posizione corrente di un dispositivo.
Aggiunta di una mappa
L'aggiunta di una mappa a un'applicazione viene eseguita aggiungendo un'istanza MKMapView
alla gerarchia di visualizzazione, come illustrato di seguito:
// map is an MKMapView declared as a class variable
map = new MKMapView (UIScreen.MainScreen.Bounds);
View = map;
MKMapView
è una sottoclasse UIView
che visualizza una mappa. Aggiungendo semplicemente la mappa usando il codice precedente, viene eseguita una mappa interattiva:
Stile mappa
MKMapView
supporta 3 diversi stili di mappe. Per applicare uno stile mappa, è sufficiente impostare la MapType
proprietà su un valore dell'enumerazione MKMapType
:
map.MapType = MKMapType.Standard; //road map
map.MapType = MKMapType.Satellite;
map.MapType = MKMapType.Hybrid;
Lo screenshot seguente mostra i diversi stili di mappa disponibili:
Panoramica e zoom
MKMapView
include il supporto per le funzionalità di interattività della mappa, ad esempio:
- Zoom tramite un movimento di avvicinamento delle dita
- Panoramica tramite un movimento di panoramica
Queste funzionalità possono essere abilitate o disabilitate semplicemente impostando le ZoomEnabled
proprietà e ScrollEnabled
dell'istanza MKMapView
, dove il valore predefinito è true per entrambi. Ad esempio, per visualizzare una mappa statica, è sufficiente impostare le proprietà appropriate su false:
map.ZoomEnabled = false;
map.ScrollEnabled = false;
Ubicazione degli utenti
Oltre all'interazione dell'utente, MKMapView
include anche il supporto predefinito per la visualizzazione della posizione del dispositivo. A tale scopo, viene usato il framework core location . Prima di poter accedere alla posizione dell'utente, è necessario richiedere all'utente. A tale scopo, creare un'istanza di CLLocationManager
e chiamare RequestWhenInUseAuthorization
.
CLLocationManager locationManager = new CLLocationManager();
locationManager.RequestWhenInUseAuthorization();
//locationManager.RequestAlwaysAuthorization(); //requests permission for access to location data while running in the background
Si noti che nelle versioni di iOS precedenti alla 8.0, il tentativo di chiamare RequestWhenInUseAuthorization
genererà un errore. Assicurarsi di controllare la versione di iOS prima di effettuare tale chiamata se si intende supportare le versioni precedenti a 8.
L'accesso alla posizione dell'utente richiede anche modifiche a Info.plist. È necessario impostare le chiavi seguenti relative ai dati del percorso:
- NSLocationWhenInUseUsageDescription: per l'accesso al percorso dell'utente quando interagisce con l'app.
- NSLocationAlwaysUsageDescription: per l'accesso dell'app al percorso dell'utente in background.
È possibile aggiungere tali chiavi aprendo Info.plist e selezionando Origine nella parte inferiore dell'editor.
Dopo aver aggiornato Info.plist e aver richiesto all'utente l'autorizzazione per accedere alla posizione, è possibile visualizzare la posizione dell'utente sulla mappa impostando la ShowsUserLocation
proprietà su true:
map.ShowsUserLocation = true;
Annotazioni
MKMapView
supporta anche la visualizzazione di immagini, note come annotazioni, su una mappa. Possono essere immagini personalizzate o pin definiti dal sistema di vari colori. Ad esempio, lo screenshot seguente mostra una mappa con un segnaposto e un'immagine personalizzata:
Aggiunta di un'annotazione
Un'annotazione ha due parti:
- Oggetto
MKAnnotation
, che include i dati del modello relativi all'annotazione, ad esempio il titolo e la posizione dell'annotazione. - Oggetto
MKAnnotationView
, che contiene l'immagine da visualizzare e, facoltativamente, un callout visualizzato quando l'utente tocca l'annotazione.
Map Kit usa il modello di delega iOS per aggiungere annotazioni a una mappa, in cui la Delegate
proprietà di è impostata su un'istanza MKMapView
di un oggetto MKMapViewDelegate
. Si tratta dell'implementazione di questo delegato responsabile della restituzione di per un'annotazione MKAnnotationView
.
Per aggiungere un'annotazione, prima viene aggiunta l'annotazione chiamando AddAnnotations
sull'istanza MKMapView
di :
// add an annotation
map.AddAnnotations (new MKPointAnnotation (){
Title="MyAnnotation",
Coordinate = new CLLocationCoordinate2D (42.364260, -71.120824)
});
Quando la posizione dell'annotazione diventa visibile sulla mappa, chiama il MKMapView
metodo del GetViewForAnnotation
delegato per ottenere l'oggetto MKAnnotationView
da visualizzare.
Ad esempio, il codice seguente restituisce un oggetto fornito dal MKPinAnnotationView
sistema:
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;
}
Riutilizzo delle annotazioni
Per risparmiare memoria, MKMapView
consente di raggruppare le visualizzazioni di annotazione per il riutilizzo, in modo analogo al modo in cui vengono riutilizzate le celle della tabella. L'acquisizione di una visualizzazione di annotazione dal pool viene eseguita con una chiamata a DequeueReusableAnnotation
:
MKAnnotationView pinView = (MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);
Visualizzazione dei callout
Come accennato in precedenza, un'annotazione può facoltativamente mostrare un callout. Per visualizzare un callout è sufficiente impostare su CanShowCallout
true in MKAnnotationView
. Ciò comporta la visualizzazione del titolo dell'annotazione quando viene toccata l'annotazione, come illustrato di seguito:
Personalizzazione del callout
Il callout può anche essere personalizzato per mostrare le visualizzazioni accessorie sinistra e destra, come illustrato di seguito:
pinView.RightCalloutAccessoryView = UIButton.FromType (UIButtonType.DetailDisclosure);
pinView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile ("monkey.png"));
Questo codice genera il callout seguente:
Per gestire l'utente toccando l'accessorio destro, è sufficiente implementare il CalloutAccessoryControlTapped
metodo in MKMapViewDelegate
:
public override void CalloutAccessoryControlTapped (MKMapView mapView, MKAnnotationView view, UIControl control)
{
...
}
Sovrimpressioni
Un altro modo per eseguire il layer della grafica su una mappa consiste nell'usare le sovrimpressioni. Le sovrimpressioni supportano contenuto grafico di tipo disegno che viene ridimensionato con la mappa quando si esegue lo zoom. iOS offre supporto per diversi tipi di sovrimpressione, tra cui:
- Poligoni: comunemente usato per evidenziare alcune aree in una mappa.
- Polilinee: spesso viene visualizzato quando viene visualizzato un itinerario.
- Cerchi : consente di evidenziare un'area circolare di una mappa.
Inoltre, è possibile creare sovrimpressioni personalizzate per mostrare geometrie arbitrarie con codice di disegno granulare e personalizzato. Ad esempio, il radar meteo sarebbe un buon candidato per una sovrimpressione personalizzata.
Aggiunta di una sovrimpressione
Analogamente alle annotazioni, l'aggiunta di una sovrimpressione prevede 2 parti:
- Creazione di un oggetto modello per la sovrimpressione e aggiunta all'oggetto
MKMapView
. - Creazione di una visualizzazione per la sovrimpressione in
MKMapViewDelegate
.
Il modello per la sovrimpressione può essere qualsiasi MKShape
sottoclasse. Xamarin.iOS include MKShape
sottoclassi per poligoni, polilinee e cerchi, rispettivamente tramite le MKPolygon
classi e MKCircle
. MKPolyline
Ad esempio, il codice seguente viene usato per aggiungere un oggetto MKCircle
:
var circleOverlay = MKCircle.Circle (mapCenter, 1000);
map.AddOverlay (circleOverlay);
La visualizzazione per una sovrimpressione è un'istanza MKOverlayView
restituita da GetViewForOverlay
in MKMapViewDelegate
. Ognuno MKShape
ha un oggetto corrispondente MKOverlayView
che sa come visualizzare la forma specificata. Perché MKPolygon
è MKPolygonView
presente . Analogamente, MKPolyline
corrisponde a MKPolylineView
e per MKCircle
è MKCircleView
presente .
Ad esempio, il codice seguente restituisce un oggetto MKCircleView
per un MKCircle
oggetto :
public override MKOverlayView GetViewForOverlay (MKMapView mapView, NSObject overlay)
{
var circleOverlay = overlay as MKCircle;
var circleView = new MKCircleView (circleOverlay);
circleView.FillColor = UIColor.Blue;
return circleView;
}
Verrà visualizzato un cerchio sulla mappa come illustrato:
Ricerca locale
iOS include un'API di ricerca locale con Map Kit, che consente ricerche asincrone di punti di interesse in un'area geografica specificata.
Per eseguire una ricerca locale, un'applicazione deve seguire questa procedura:
- Creare l'oggetto
MKLocalSearchRequest
. - Creare un
MKLocalSearch
oggetto daMKLocalSearchRequest
. - Chiamare il
Start
metodo sull'oggettoMKLocalSearch
. - Recuperare l'oggetto
MKLocalSearchResponse
in un callback.
L'API di ricerca locale non fornisce alcuna interfaccia utente. Non richiede nemmeno l'uso di una mappa. Tuttavia, per usare praticamente la ricerca locale, un'applicazione deve fornire un modo per specificare una query di ricerca e visualizzare i risultati. Inoltre, poiché i risultati conterranno i dati sulla posizione, spesso sarà opportuno visualizzarli su una mappa.
Aggiunta di un'interfaccia utente di ricerca locale
Un modo per accettare l'input di ricerca è con un UISearchBar
oggetto , fornito da e UISearchController
visualizzerà i risultati in una tabella.
Il codice seguente aggiunge ( UISearchController
che ha una proprietà della barra di ricerca) nel ViewDidLoad
metodo di 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;
Si noti che l'utente è responsabile dell'incorporazione dell'oggetto barra di ricerca nell'interfaccia utente. In questo esempio, è stato assegnato a TitleView della barra di spostamento, ma se non si usa un controller di spostamento nell'applicazione sarà necessario trovare un'altra posizione per visualizzarla.
In questo frammento di codice è stato creato un altro controller di visualizzazione personalizzato, searchResultsController
che visualizza i risultati della ricerca e quindi è stato usato questo oggetto per creare l'oggetto controller di ricerca. È stato creato anche un nuovo updater di ricerca, che diventa attivo quando l'utente interagisce con la barra di ricerca. Riceve notifiche sulle ricerche con ogni sequenza di tasti ed è responsabile dell'aggiornamento dell'interfaccia utente.
Di seguito verrà illustrato come implementare sia e searchResultsController
più searchResultsUpdater
avanti in questa guida.
In questo modo viene visualizzata una barra di ricerca sulla mappa, come illustrato di seguito:
Visualizzazione dei risultati della ricerca
Per visualizzare i risultati della ricerca, è necessario creare un controller di visualizzazione personalizzato; normalmente un oggetto UITableViewController
. Come illustrato in precedenza, viene searchResultsController
passato al costruttore di searchController
quando viene creato.
Il codice seguente è un esempio di come creare questo controller di visualizzazione personalizzato:
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);
}
});
}
}
Aggiornamento dei risultati della ricerca
Funge SearchResultsUpdater
da mediatore tra la barra di ricerca e i searchController
risultati della ricerca.
In questo esempio è necessario prima creare il metodo di ricerca in SearchResultsViewController
. A tale scopo, è necessario creare un MKLocalSearch
oggetto e usarlo per eseguire una ricerca di , MKLocalSearchRequest
i risultati vengono recuperati in un callback passato al Start
metodo dell'oggetto MKLocalSearch
. I risultati vengono quindi restituiti in un MKLocalSearchResponse
oggetto contenente una matrice di MKMapItem
oggetti:
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);
}
});
}
Quindi, in MapViewController
verrà creata un'implementazione personalizzata di UISearchResultsUpdating
, che viene assegnata alla SearchResultsUpdater
proprietà di searchController
nella sezione Aggiunta di un'interfaccia utente di ricerca locale:
public class SearchResultsUpdator : UISearchResultsUpdating
{
public event Action<string> UpdateSearchResults = delegate {};
public override void UpdateSearchResultsForSearchController (UISearchController searchController)
{
this.UpdateSearchResults (searchController.SearchBar.Text);
}
}
L'implementazione precedente aggiunge un'annotazione alla mappa quando viene selezionato un elemento dai risultati, come illustrato di seguito:
Importante
UISearchController
è stato implementato in iOS 8. Se vuoi supportare i dispositivi prima di questo, dovrai usare UISearchDisplayController
.
Riepilogo
Questo articolo ha esaminato il framework map kit per iOS. In primo luogo, è stato esaminato come la classe consente l'inserimento MKMapView
di mappe interattive in un'applicazione. Ha quindi illustrato come personalizzare ulteriormente le mappe usando annotazioni e sovrapposizioni. Infine, ha esaminato le funzionalità di ricerca locali aggiunte a Map Kit con iOS 6.1, mostrando come usare query basate sulla posizione per i punti di interesse e aggiungerle a una mappa.