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 不再需要帮助,因为它很快就会被弃用。阿们。
我一直在努力让我之前开发的地图集群变得友好,我遇到了一些使用 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 不再需要帮助,因为它很快就会被弃用。阿们。