Condividi tramite


Nuove funzionalità in MapKit in iOS 11

iOS 11 aggiunge le nuove funzionalità seguenti a MapKit:

Mappa che mostra i marcatori cluster e il pulsante della bussola

Raggruppamento automatico dei marcatori durante lo zoom

L'esempio illustra come implementare la nuova funzionalità di clustering di annotazione iOS 11.

1. Creare una sottoclasse MKPointAnnotation

La classe di annotazione punto rappresenta ogni marcatore sulla mappa. Possono essere aggiunti singolarmente usando MapView.AddAnnotation() o da una matrice usando MapView.AddAnnotations().

Le classi di annotazioni punto non hanno una rappresentazione visiva, sono necessarie solo per rappresentare i dati associati al marcatore (soprattutto, la proprietà che è la Coordinate sua latitudine e longitudine sulla mappa) ed eventuali proprietà personalizzate:

public class Bike : MKPointAnnotation
{
  public BikeType Type { get; set; } = BikeType.Tricycle;
  public Bike(){}
  public Bike(NSNumber lat, NSNumber lgn, NSNumber type)
  {
    Coordinate = new CLLocationCoordinate2D(lat.NFloatValue, lgn.NFloatValue);
    switch(type.NUIntValue) {
      case 0:
        Type = BikeType.Unicycle;
        break;
      case 1:
        Type = BikeType.Tricycle;
        break;
    }
  }
}

2. Creare una sottoclasse MKMarkerAnnotationView per singoli marcatori

La visualizzazione delle annotazioni del marcatore è la rappresentazione visiva di ogni annotazione ed è in stile usando proprietà come:

  • MarkerTintColor : colore per il marcatore.
  • GlyphText : testo visualizzato nel marcatore.
  • GlyphImage : imposta l'immagine visualizzata nel marcatore.
  • DisplayPriority : determina l'ordine z (comportamento di impilamento) quando la mappa è affollata di marcatori. Usare uno di Required, DefaultHigho DefaultLow.

Per supportare il clustering automatico, è necessario impostare anche:

  • ClusteringIdentifier : controlla quali marcatori vengono raggruppati tra loro. È possibile usare lo stesso identificatore per tutti i marcatori o usare identificatori diversi per controllare la modalità di raggruppamento.
[Register("BikeView")]
public class BikeView : MKMarkerAnnotationView
{
  public static UIColor UnicycleColor = UIColor.FromRGB(254, 122, 36);
  public static UIColor TricycleColor = UIColor.FromRGB(153, 180, 44);
  public override IMKAnnotation Annotation
  {
    get {
      return base.Annotation;
    }
    set {
      base.Annotation = value;

      var bike = value as Bike;
      if (bike != null){
        ClusteringIdentifier = "bike";
        switch(bike.Type){
          case BikeType.Unicycle:
            MarkerTintColor = UnicycleColor;
            GlyphImage = UIImage.FromBundle("Unicycle");
            DisplayPriority = MKFeatureDisplayPriority.DefaultLow;
            break;
          case BikeType.Tricycle:
            MarkerTintColor = TricycleColor;
            GlyphImage = UIImage.FromBundle("Tricycle");
            DisplayPriority = MKFeatureDisplayPriority.DefaultHigh;
            break;
        }
      }
    }
  }

3. Creare un oggetto MKAnnotationView per rappresentare i cluster di marcatori

Anche se la visualizzazione di annotazione che rappresenta un cluster di marcatori potrebbe essere un'immagine semplice, gli utenti si aspettano che l'app fornisca segnali visivi sul numero di marcatori raggruppati.

L'esempio usa CoreGraphics per eseguire il rendering del numero di marcatori nel cluster, nonché una rappresentazione del grafico a cerchio della proporzione di ogni tipo di marcatore.

È anche necessario impostare:

  • DisplayPriority : determina l'ordine z (comportamento di impilamento) quando la mappa è affollata di marcatori. Usare uno di Required, DefaultHigho DefaultLow.
  • CollisionMode : Circle o Rectangle.
[Register("ClusterView")]
public class ClusterView : MKAnnotationView
{
  public static UIColor ClusterColor = UIColor.FromRGB(202, 150, 38);
  public override IMKAnnotation Annotation
  {
    get {
      return base.Annotation;
    }
    set {
      base.Annotation = value;
      var cluster = MKAnnotationWrapperExtensions.UnwrapClusterAnnotation(value);
      if (cluster != null)
      {
        var renderer = new UIGraphicsImageRenderer(new CGSize(40, 40));
        var count = cluster.MemberAnnotations.Length;
        var unicycleCount = CountBikeType(cluster.MemberAnnotations, BikeType.Unicycle);

        Image = renderer.CreateImage((context) => {
          // Fill full circle with tricycle color
          BikeView.TricycleColor.SetFill();
          UIBezierPath.FromOval(new CGRect(0, 0, 40, 40)).Fill();
          // Fill pie with unicycle color
          BikeView.UnicycleColor.SetFill();
          var piePath = new UIBezierPath();
          piePath.AddArc(new CGPoint(20,20), 20, 0, (nfloat)(Math.PI * 2.0 * unicycleCount / count), true);
          piePath.AddLineTo(new CGPoint(20, 20));
          piePath.ClosePath();
          piePath.Fill();
          // Fill inner circle with white color
          UIColor.White.SetFill();
          UIBezierPath.FromOval(new CGRect(8, 8, 24, 24)).Fill();
          // Finally draw count text vertically and horizontally centered
          var attributes = new UIStringAttributes() {
            ForegroundColor = UIColor.Black,
            Font = UIFont.BoldSystemFontOfSize(20)
          };
          var text = new NSString($"{count}");
          var size = text.GetSizeUsingAttributes(attributes);
          var rect = new CGRect(20 - size.Width / 2, 20 - size.Height / 2, size.Width, size.Height);
          text.DrawString(rect, attributes);
        });
      }
    }
  }
  public ClusterView(){}
  public ClusterView(MKAnnotation annotation, string reuseIdentifier) : base(annotation, reuseIdentifier)
  {
    DisplayPriority = MKFeatureDisplayPriority.DefaultHigh;
    CollisionMode = MKAnnotationViewCollisionMode.Circle;
    // Offset center point to animate better with marker annotations
    CenterOffset = new CoreGraphics.CGPoint(0, -10);
  }
  private nuint CountBikeType(IMKAnnotation[] members, BikeType type) {
    nuint count = 0;
    foreach(Bike member in members){
      if (member.Type == type) ++count;
    }
    return count;
  }
}

4. Registrare le classi di visualizzazione

Quando il controllo visualizzazione mappa viene creato e aggiunto a una visualizzazione, registrare i tipi di visualizzazione delle annotazioni per abilitare il comportamento automatico del clustering man mano che viene eseguito lo zoom avanti e indietro della mappa:

MapView.Register(typeof(BikeView), MKMapViewDefault.AnnotationViewReuseIdentifier);
MapView.Register(typeof(ClusterView), MKMapViewDefault.ClusterAnnotationViewReuseIdentifier);

5. Eseguire il rendering della mappa!

Quando viene eseguito il rendering della mappa, i marcatori di annotazione verranno raggruppati o sottoposti a rendering a seconda del livello di zoom. Man mano che cambia il livello di zoom, i marcatori si animano all'interno e all'esterno dei cluster.

Simulatore che mostra i marcatori cluster sulla mappa

Per altre informazioni sulla visualizzazione dei dati con MapKit, vedere la sezione Mappe.

Pulsante bussola

iOS 11 aggiunge la possibilità di estrarre la bussola dalla mappa ed eseguirne il rendering altrove nella visualizzazione.

Creare un pulsante simile a una bussola (inclusa l'animazione in tempo reale quando viene modificato l'orientamento della mappa) ed eseguirne il rendering su un altro controllo.

Pulsante Bussola nella barra di spostamento

Il codice seguente crea un pulsante bussola ed esegue il rendering sulla barra di spostamento:

var compass = MKCompassButton.FromMapView(MapView);
compass.CompassVisibility = MKFeatureVisibility.Visible;
NavigationItem.RightBarButtonItem = new UIBarButtonItem(compass);
MapView.ShowsCompass = false; // so we don't have two compasses!

La ShowsCompass proprietà può essere utilizzata per controllare la visibilità della bussola predefinita all'interno della visualizzazione mappa.

Visualizzazione scala

Aggiungere la scala altrove nella vista usando il MKScaleView.FromMapView() metodo per ottenere un'istanza della visualizzazione di scala da aggiungere altrove nella gerarchia di visualizzazione.

Ridimensionare la visualizzazione sovrapposta su una mappa

var scale = MKScaleView.FromMapView(MapView);
scale.LegendAlignment = MKScaleViewAlignment.Trailing;
scale.TranslatesAutoresizingMaskIntoConstraints = false;
View.AddSubview(scale); // constraints omitted for simplicity
MapView.ShowsScale = false; // so we don't have two scale displays!

La ShowsScale proprietà può essere utilizzata per controllare la visibilità della bussola predefinita all'interno della visualizzazione mappa.

Pulsante Rilevamento utenti

Il pulsante di rilevamento utente centra la mappa sulla posizione corrente dell'utente. Usare il MKUserTrackingButton.FromMapView() metodo per ottenere un'istanza del pulsante, applicare le modifiche di formattazione e aggiungere altrove nella gerarchia di visualizzazione.

Pulsante Posizione utente sovrapposto su una mappa

var button = MKUserTrackingButton.FromMapView(MapView);
button.Layer.BackgroundColor = UIColor.FromRGBA(255,255,255,80).CGColor;
button.Layer.BorderColor = UIColor.White.CGColor;
button.Layer.BorderWidth = 1;
button.Layer.CornerRadius = 5;
button.TranslatesAutoresizingMaskIntoConstraints = false;
View.AddSubview(button); // constraints omitted for simplicity