GetViewForAnnotation 在加载自定义一个后返回默认的红色图钉

GetViewForAnnotation returning default red pin after loading custom one

我一直在努力让我之前开发的地图集群变得友好,我遇到了一些使用 nugget ClusterKit 的很酷的例子,一切似乎都工作正常,集群去集群明智,但是我的一些已经加载的图钉正在恢复到默认的红色别针。我的图钉添加正确并且它们都很好地聚集在一起,但是当我的地图区域发生变化然后返回到先前加载的部分(带有加载的图钉)时,它们几乎总是全部恢复为红色 iOS 图钉 在做了更多之后挖掘,最初我的注释作为 Xamarin.iOS.ClusterKit.CKCluster 类型传递给 GetViewForAnnotation(好)但是在“初始加载”之后,pin 将是红色的,所以它不再是 CKCluster 类型,它现在是(默认 MKAnnotationView)然后删除所有聚类能力。 地图渲染器

[assembly: ExportRenderer(typeof(CustomMap), typeof(iOSMapRenderer))]

ClusterMap _clusterMap;
MKMapView Map => Control as MKMapView;
CustomMap PCLMap => Element as CustomMap;
_testClustering = true;
protected override void OnElementChanged(ElementChangedEventArgs<CustomMap> e)
{

   base.OnElementChanged(e);

    if (e.OldElement != null && Map != null)
    ...

    if (e.NewElement == null) return;
    if (_testClustering)
    {
      _clusterMap = new ClusterMap(Map);
    }
    if (Map == null) return;
    Map.GetViewForAnnotation = GetViewForAnnotation;
    Map.DidSelectAnnotationView += OnDidSelectAnnotationView;
    Map.RegionChanged += OnMapRegionChanged;
    ...
    UpdatePins(true);
    PCLMap.PropertyChanged += OnMapPropertyChanged;
}

void OnMapPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == CustomMap.Pins)
        UpdatePins();
    else if(e.PropertyName == CustomMap.SelectedPin)
            SetSelectedPin();
    else if(e.PropertyName == CustomMap.MapRegion)
           UpdateMapRegion();
}

void UpdatePins(firstTime)
{
   if (_testClustering)
       {
         _clusterMap.ClusterManager
                  .RemoveAnnotations(_clusterMap.ClusterManager.Annotations);
        }
   else
        {
          Map.RemoveAnnotations(Map.Annotations);
        }

   foreach (var i in PCLMap.Pins)
   {
       i.PropertyChanged -= OnPinPropertyChanged;
       AddPin(i);
   }
   if (firstTime)
   {
       if (PCLMap.Pins is INotifyCollectionChanged observable)
        {
          observable.CollectionChanged += OnCollectionChanged;
        }
    }
}

 void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
  if (e.Action == NotifyCollectionChangedAction.Add)
  {
    foreach (CustomPin pin in e.NewItems)
    {
        AddPin(pin);
    }
  }
  else if (e.Action == NotifyCollectionChangedAction.Reset)
  {
      IEnumerable<IMKAnnotation> annotations = _testClustering ? _clusterMap.ClusterManager.Annotations : Map.Annotations;

      foreach (var annotation in annotations.OfType<MyMapAnnotation>())
      {
         annotation.CustomPin.PropertyChanged -= OnPinPropertyChanged;
      }
      UpdatePins(false);
    }
}

      void AddPin(CustomPin pin)
    {
       var annotation = new MyMapAnnotation(pin);
       if (_testClustering)
       {
          _clusterMap.ClusterManager.AddAnnotation(annotation);
       }
       else
       {
          Map.AddAnnotation(annotation);
       }
    }
    
    public virtual MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
    {
       var clusterAnnotation = annotation as CKCluster;
       var createInitialClusterView = false;
       MKAnnotationView annotationView = null;
       MyMapAnnotation customAnnotation = null;
       if (clusterAnnotation == null)
       {
         //for non clustering map -- 
         //but gets called after initial load because pin is no   
         //Longer recognized as CKCluster
          customAnnotation = annotation as MyMapAnnotation;
       }
       else
       {
         if (clusterAnnotation.Count > 1)
         {
             var clusterPin = PCLMap.GetClusteredPin?.Invoke(null, clusterAnnotation.Annotations.OfType<MyMapAnnotation>().Select(i => i.CustomPin));
             if (clusterPin == null)
             {
                createInitialClusterView = true;
             }
             else
             {
               customAnnotation = new MyMapAnnotation(clusterPin);
             }
         }
         else  
         {
            customAnnotation = clusterAnnotation.FirstAnnotation as MyMapAnnotation;
         }
       }
       // IF we need to create a new cluster
       if (createInitialClusterView)
       {
          
           annotationView = new ClusterAnnotationView(clusterAnnotation, 
          
        else 
        {
           if (customAnnotation == null)
           {
               return null;
           }
    
          if (annotationView == null)
           {
               annotationView = new MKAnnotationView(customAnnotation, 
                                AnnotationIdentifier);
               annotationView.Layer.AnchorPoint = new 
                                       CGPoint(customAnnotation.CustomPin.AnchorPoint.X, 
           }
          else
          {
            annotationView.Annotation = customAnnotation;
          }
          annotationView.CanShowCallout = customAnnotation.CustomPin.ShowCallout;
          SetAnnotationViewVisibility(annotationView, customAnnotation.CustomPin);
          UpdateImage(annotationView, customAnnotation.CustomPin);
                 
        }
        return annotationView; // returning default MKAnnotationView 
    }

ClusterMap

//initializing example
 public class ClusterMap : CKMap
{
   MKMapView _mkMapView;

public ClusterMap(MKMapView mapView)
{
   _mkMapView = mapView;
}
CKClusterManager mapView;
public override CKClusterManager ClusterManager => LazyInitializer.EnsureInitialized(ref _clusterManager, () =>
{
   _clusterManager = new CKClusterManager();
   _clusterManager.Map = this;
   _clusterManager.Algorithm = new CKNonHierarchicalDistanceBasedAlgorithm();

    return _clusterManager;
 });

public override MKMapRect VisibleMapRect => _mkMapView.VisibleMapRect;

public override void AddClusters(CKCluster[] clusters)
{
   _mkMapView.AddAnnotations(clusters);
}

public override void DeselectCluster(CKCluster cluster, bool animated)
{
   if (! _mkMapView.SelectedAnnotations.Contains(cluster)) return;
   _mkMapView.DeselectAnnotation(cluster, animated);
}

public override void PerformAnimations(CKClusterAnimation[] animations, Action<bool> completion)
{
    foreach (var animation in animations)
    {
       animation.Cluster.Coordinate = animation.From;
    }
  //... performs clustering animation
}

public override void RemoveClusters(CKCluster[] clusters)
{
    _mkMapView.RemoveAnnotations(clusters);
}

public override void SelectCluster(CKCluster cluster, bool animated)
{
   //TODO Zoom in
}

 public MKMapRect MKMapRectByAddingPoint(MKMapRect rect, MKMapPoint point)
{
    return MKMapRect.Union(rect, new MKMapRect() { Origin = point, Size = MKMapRect.Null.Size });
}

MyMapAnnotation

internal class MyMapAnnotation : MKAnnotation
{
   CLLocationCoordinate2D _coordinate;
   readonly CustomPin _formsPin;
  public override string Title
  {
     get
     {
       return _formsPin.Label;
      }
   }

 public override CLLocationCoordinate2D Coordinate
 {
    get { return _coordinate; }
 }

 public CustomPin CustomPin
 {
    get { return _formsPin; }
 }

 public override void SetCoordinate(CLLocationCoordinate2D value)
 {
    if (!value.IsValid()) return;
    _formsPin.Position = value.ToPosition();
    _coordinate = value;
 }

  public void SetCoordinateOriginal(CLLocationCoordinate2D value)
  {
    SetCoordinate(value);
  }

  public MyMapAnnotation(CustomPin pin)
  {
    _formsPin = pin;
    _coordinate = pin.Position.ToLocationCoordinate();
    _formsPin.PropertyChanged += FormsPinPropertyChanged;
  }
 public void SetCoordinateInternal(CLLocationCoordinate2D value, bool triggerObserver)
 {
    if (triggerObserver)
         WillChangeValue("coordinate");
    SetCoordinate(value);
    if (triggerObserver)
        DidChangeValue("coordinate");
  }
 System.ComponentModel.PropertyChangedEventArgs e)
 {
    if (e.PropertyName == nameof(CustomPin.Label))
    {
        WillChangeValue("title");
        DidChangeValue("title");
    }
 }

 protected override void Dispose(bool disposing)
 {
    base.Dispose(disposing);
    if (disposing)
       _formsPin.PropertyChanged -= FormsPinPropertyChanged;
  }

}

想通了。打开我的 GetViewForAnnotation 中的问题。我的注释被封装到 AnnotationWrapper 而不是注释中。然后,这阻止了我将我的案例中的任何内容投射到我的 CustomAnnotationView 中。我最终引用了 NSObject 并引用了 CKCluster 项(原始类型)。然后我对方法的流程做了一些调整,但我能够得到我需要的东西,现在一切正常。我得到了一些帮助,但我希望 Xamarin 不再需要帮助,因为它很快就会被弃用。阿们。