iOS 11 の MapKit の新機能

iOS 11 では、MapKit に次の新機能が追加されます。

クラスター化されたマーカーとコンパス ボタンを示すマップ

ズーム中にマーカーを自動的にグループ化する

サンプルの MapKit サンプル "Tandm" は、新しい iOS 11 注釈クラスタリング機能を実装する方法を示しています。

1. サブクラスを作成するMKPointAnnotation

ポイント注釈クラスは、マップ上の各マーカーを表します。 を使用して、または を使用して MapView.AddAnnotation() 配列 MapView.AddAnnotations()から個別に追加できます。

ポイント注釈クラスには視覚的表現はありません。マーカーに関連付けられているデータ (最も重要なのは、マップ上の緯度と経度であるプロパティ)、 Coordinate およびカスタム プロパティを表すためにのみ必要です。

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. 単一マーカーのサブクラスを作成するMKMarkerAnnotationView

マーカー注釈ビューは、各注釈の視覚的表現であり、次のようなプロパティを使用してスタイルが設定されます。

  • MarkerTintColor – マーカーの色。
  • GlyphText – マーカーに表示されるテキスト。
  • GlyphImage – マーカーに表示されるイメージを設定します。
  • DisplayPriority – マップがマーカーで混雑している場合の z オーダー (積み重ね動作) を決定します。 、DefaultHigh、または のいずれかをRequired使用しますDefaultLow

自動クラスタリングをサポートするには、次も設定する必要があります。

  • ClusteringIdentifier – クラスター化されるマーカーを制御します。 すべてのマーカーに同じ識別子を使用することも、異なる識別子を使用してグループ化方法を制御することもできます。
[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. マーカーのクラスターを表す を MKAnnotationView 作成する

マーカーのクラスターを表す注釈ビューは単純な画像である 可能性 があります。一方、ユーザーは、複数のマーカーがグループ化されたマーカーの数に関する視覚的な手掛かりをアプリに提供することを期待しています。

このサンプル コードでは、CoreGraphics を使用してクラスター内のマーカーの数と、各マーカーの種類の割合の円グラフ表現をレンダリングします。

次の設定も行う必要があります。

  • DisplayPriority – マップがマーカーで混雑している場合の z オーダー (積み重ね動作) を決定します。 、DefaultHigh、または のいずれかをRequired使用しますDefaultLow
  • CollisionModeCircle または 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. ビュー クラスを登録する

マップ ビュー コントロールを作成してビューに追加する場合は、注釈ビューの種類を登録して、マップの拡大と縮小時のクラスタリングの自動動作を有効にします。

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

5. マップをレンダリングします。

マップをレンダリングすると、ズーム レベルに応じて注釈マーカーがクラスター化またはレンダリングされます。 ズーム レベルが変化すると、マーカーはクラスター内およびクラスター外でアニメーション化されます。

マップ上のクラスター化マーカーを示すシミュレーター

MapKit を使用したデータの表示の詳細については、「Maps」セクションを参照してください。

コンパス ボタン

iOS 11 では、コンパスをマップからポップしてビュー内の他の場所にレンダリングする機能が追加されています。 例については、 Tandm サンプル アプリ を参照してください。

コンパスのように見えるボタン (マップの向きが変更されたときのライブ アニメーションを含む) を作成し、別のコントロールにレンダリングします。

ナビゲーション バーの [コンパス] ボタン

次のコードでは、コンパス ボタンを作成し、ナビゲーション バーにレンダリングします。

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

プロパティを ShowsCompass 使用して、マップ ビュー内の既定のコンパスの表示を制御できます。

スケール ビュー

メソッドを使用して MKScaleView.FromMapView() ビューの他の場所にスケールを追加し、ビュー階層内の他の場所に追加するスケール ビューのインスタンスを取得します。

マップ上にオーバーレイされたスケール ビュー

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!

プロパティを ShowsScale 使用して、マップ ビュー内の既定のコンパスの表示を制御できます。

[ユーザー追跡] ボタン

ユーザー追跡ボタンは、ユーザーの現在の場所にマップを中央に配置します。 ボタンのインスタンスを MKUserTrackingButton.FromMapView() 取得し、書式設定の変更を適用し、ビュー階層内の他の場所に追加するには、 メソッドを使用します。

マップ上にオーバーレイされた [ユーザーの場所] ボタン

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