Partilhar via


Novos recursos do MapKit no iOS 11

O iOS 11 adiciona os seguintes novos recursos ao MapKit:

Mapa mostrando marcadores agrupados e botão de bússola

Agrupar marcadores automaticamente durante o zoom

O exemplo mostra como implementar o novo recurso de clustering de anotações do iOS 11.

1. Criar uma MKPointAnnotation subclasse

A classe de anotação de ponto representa cada marcador no mapa. Eles podem ser adicionados individualmente usando MapView.AddAnnotation() ou a partir de uma matriz usando MapView.AddAnnotations()o .

As classes de anotação de ponto não têm uma representação visual, elas são necessárias apenas para representar os dados associados ao marcador (o mais importante, a Coordinate propriedade que é sua latitude e longitude no mapa) e quaisquer propriedades personalizadas:

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. Criar uma MKMarkerAnnotationView subclasse para marcadores únicos

O modo de exibição de anotação de marcador é a representação visual de cada anotação e é estilizado usando propriedades como:

  • MarkerTintColor – A cor do marcador.
  • GlyphText – Texto exibido no marcador.
  • GlyphImage – Define a imagem que é exibida no marcador.
  • DisplayPriority – Determina a ordem z (comportamento de empilhamento) quando o mapa está repleto de marcadores. Use um dos Required, DefaultHighou DefaultLow.

Para oferecer suporte ao clustering automático, você também deve definir:

  • ClusteringIdentifier – Controla quais marcadores são agrupados. Você pode usar o mesmo identificador para todos os marcadores ou usar identificadores diferentes para controlar a maneira como eles são agrupados.
[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. Crie um MKAnnotationView para representar clusters de marcadores

Embora o modo de exibição de anotação que representa um cluster de marcadores possa ser uma imagem simples, os usuários esperam que o aplicativo forneça pistas visuais sobre quantos marcadores foram agrupados.

O exemplo usa CoreGraphics para renderizar o número de marcadores no cluster, bem como uma representação de gráfico circular da proporção de cada tipo de marcador.

Você também deve definir:

  • DisplayPriority – Determina a ordem z (comportamento de empilhamento) quando o mapa está repleto de marcadores. Use um dos Required, DefaultHighou DefaultLow.
  • CollisionModeCircle ou 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. Registre as classes de exibição

Quando o controle de exibição de mapa estiver sendo criado e adicionado a uma exibição, registre os tipos de exibição de anotação para habilitar o comportamento de clustering automático à medida que o mapa é ampliado e reduzido:

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

5. Renderize o mapa!

Quando o mapa é renderizado, os marcadores de anotação serão agrupados ou renderizados, dependendo do nível de zoom. À medida que o nível de zoom muda, os marcadores são animados dentro e fora dos clusters.

Simulador mostrando marcadores agrupados no mapa

Consulte a seção Mapas para obter mais informações sobre como exibir dados com o MapKit.

Botão da Bússola

O iOS 11 adiciona a capacidade de tirar a bússola do mapa e renderizá-la em outro lugar da visualização.

Crie um botão que se pareça com uma bússola (incluindo animação ao vivo quando a orientação do mapa for alterada) e renderize-o em outro controle.

Botão Bússola na barra de navegação

O código abaixo cria um botão de bússola e o renderiza na barra de navegação:

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

A ShowsCompass propriedade pode ser usada para controlar a visibilidade da bússola padrão dentro da visualização de mapa.

Visualização de escala

Adicione a escala em outro lugar no modo de exibição usando o MKScaleView.FromMapView() método para obter uma instância do modo de exibição de escala para adicionar em outro lugar na hierarquia do modo de exibição.

Visualização de escala sobreposta em um mapa

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!

A ShowsScale propriedade pode ser usada para controlar a visibilidade da bússola padrão dentro da visualização de mapa.

Botão de Rastreamento de Usuário

O botão de rastreamento do usuário centraliza o mapa na localização atual do usuário. Use o MKUserTrackingButton.FromMapView() método para obter uma instância do botão, aplicar alterações de formatação e adicionar em outro lugar na hierarquia de exibição.

Botão de localização do usuário sobreposto em um mapa

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