Xamarin表单 - 使用自定义地图渲染器在地图上显示多个多边形

时间:2017-09-19 05:55:59

标签: c# xamarin xamarin.ios xamarin.forms

我已经按照this Xamarin表格教程使用自定义地图渲染器突出显示地图上的某个区域。本教程将向您展示如何在Xamarin Forms中向地图添加一个多边形,但不解释如何扩展代码以允许地图上的多个多边形。

如何调整此实现以允许iOS地图上的多个多边形?这是我的iOS代码:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.iOS
{
    public class CustomMapRenderer : MapRenderer
    {
        MKPolygonRenderer polygonRenderer;

        protected override void OnElementChanged(ElementChangedEventArgs<View> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null) {
                var nativeMap = Control as MKMapView;
                if (nativeMap != null) {
                    nativeMap.RemoveOverlays(nativeMap.Overlays);
                    nativeMap.OverlayRenderer = null;
                    polygonRenderer = null;
                }
            }

            if (e.NewElement != null) {
                var formsMap = (CustomMap)e.NewElement;
                var nativeMap = Control as MKMapView;

                nativeMap.OverlayRenderer = GetOverlayRenderer;

                CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[formsMap.ShapeCoordinates.Count];

                int index = 0;
                foreach (var position in formsMap.ShapeCoordinates)
                {
                    coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
                    index++;
                }

                var blockOverlay = MKPolygon.FromCoordinates(coords);
                nativeMap.AddOverlay(blockOverlay);
            }
        }




 MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlayWrapper)
      {
          if (polygonRenderer == null && !Equals(overlayWrapper, null)) {
              var overlay = Runtime.GetNSObject(overlayWrapper.Handle) as IMKOverlay;
              polygonRenderer = new MKPolygonRenderer(overlay as MKPolygon) {
                  FillColor = UIColor.Red,
                  StrokeColor = UIColor.Blue,
                  Alpha = 0.4f,
                  LineWidth = 9
              };
          }
          return polygonRenderer;
      }

    }
}

2 个答案:

答案 0 :(得分:5)

您的代码存在两个问题:

  1. 第一个问题出在您的if (e.NewElement != null){...}代码中。如果您想要多个多边形,formsMap.ShapeCoordinates应该是List<List<Position>>类型。所以它可以有多个多边形&#39;坐标组。代码显示时,它使用List<Position>。并且您的代码只触发nativeMap.AddOverlay(blockOverlay);一次,只会在地图中添加一个叠加层。

  2. if (polygonRenderer == null && !Equals(overlayWrapper, null))中的GetOverlayRenderer更改为if (!Equals(overlayWrapper, null))。否则,每次地图添加叠加层并触发方法时,它都会返回第一个polygonRenderer

  3. 以下是我的代码:

    1. PCL中 MainPage.xaml 中的代码:

      <ContentPage.Content>
          <local:CustomMap x:Name="customMap" MapType="Street" WidthRequest="{x:Static local:App.ScreenWidth}" HeightRequest="{x:Static local:App.ScreenHeight}" />
      </ContentPage.Content>
      
    2. 我添加了两个多边形&#39; PCL中 MainPage.xaml.cs 的位置列表:

      List<Position> pos = new List<Position> { new Position(39.939889, 116.423493), new Position(39.930622, 116.423924), new Position(39.930733,116.441135), new Position(39.939944, 116.44056) };
      List<Position> posi = new List<Position> { new Position(39.934633, 116.399921), new Position(39.929709, 116.400208), new Position(39.929792, 116.405994), new Position(39.934689,116.405526) };
      customMap.ShapeCoordinates.Add(pos);
      customMap.ShapeCoordinates.Add(posi);
      customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(39.934689, 116.405526), Distance.FromMiles(1.5)));
      
    3. PCL中 CustomMap.cs 中的代码:

      public class CustomMap : Map
      {
          public List<List<Position>> ShapeCoordinates { get; set; }
      
          public CustomMap()
          {
              ShapeCoordinates = new List<List<Position>>();
          }
      }
      
    4. iOS平台中 CustomMapRenderer.cs 中的代码:

      class CustomMapRenderer : MapRenderer
      {
          MKPolygonRenderer polygonRenderer;
      
          protected override void OnElementChanged(ElementChangedEventArgs<View> e)
          {
              base.OnElementChanged(e);
      
              if (e.OldElement != null)
              {
                  var nativeMap = Control as MKMapView;
                  if (nativeMap != null)
                  {
                      nativeMap.RemoveOverlays(nativeMap.Overlays);
                      nativeMap.OverlayRenderer = null;
                      polygonRenderer = null;
                  }
              }
      
              if (e.NewElement != null)
              {
                  var formsMap = (CustomMap)e.NewElement;
                  var nativeMap = Control as MKMapView;
                  nativeMap.OverlayRenderer = GetOverlayRenderer;
      
                  foreach (List<Position> positionList in formsMap.ShapeCoordinates)
                  {
      
                      CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[positionList.Count];
      
                      int index = 0;
                      foreach (var position in positionList)
                      {
                          coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
                          Console.WriteLine(position.Latitude +" : "+ position.Longitude);
      
                          index++;
                      }
      
      
      
                      var blockOverlay = MKPolygon.FromCoordinates(coords);
                      nativeMap.AddOverlay(blockOverlay);
      
                  }
              }
          }
      
      
      
          MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlayWrapper)
          {
              if (!Equals(overlayWrapper, null))
              {         
                  var overlay = Runtime.GetNSObject(overlayWrapper.Handle) as IMKOverlay;
                  polygonRenderer = new MKPolygonRenderer(overlay as MKPolygon)
                  {
                      FillColor = UIColor.Red,
                      StrokeColor = UIColor.Blue,
                      Alpha = 0.4f,
                      LineWidth = 9
      
                  };
              }
              return polygonRenderer;
          }
      }
      
    5. 它的工作原理如下:

      enter image description here

答案 1 :(得分:1)

在编写自己的自定义渲染器时,我通常会参考此扩展地图控件。

TKCustomMap Github Repo

查看多边形的iOS渲染器,他们只需在Forms Map上遍历多边形,然后在iOS Map中添加另一个叠加层即可。

       foreach (var position in formsMap.ShapeCoordinates)
        {
            coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
            var blockOverlay = MKPolygon.FromCoordinates(coords);
            nativeMap.AddOverlay(blockOverlay);
        }