Condividi tramite


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:

Mappa di esempio

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:

Questo screenshot mostra i diversi stili della 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;

Avviso di accesso alla posizione consentito

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:

Questo screenshot 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 MKPinAnnotationViewsistema:

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:

Titolo delle annotazioni visualizzato

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:

Callout di esempio

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 MKPolygonclassi 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 è MKPolygonViewpresente . Analogamente, MKPolyline corrisponde a MKPolylineViewe per MKCircle è MKCircleViewpresente .

Ad esempio, il codice seguente restituisce un oggetto MKCircleView per un MKCircleoggetto :

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:

Cerchio visualizzato sulla mappa

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:

  1. Creare l'oggetto MKLocalSearchRequest .
  2. Creare un MKLocalSearch oggetto da MKLocalSearchRequest .
  3. Chiamare il Start metodo sull'oggetto MKLocalSearch .
  4. 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 UISearchBaroggetto , 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:

Barra di ricerca visualizzata sulla mappa

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 searchControllerrisultati 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 , MKLocalSearchRequesti 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:

Annotazione aggiunta alla mappa quando viene selezionato un elemento dai risultati

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.