Reputation: 553
How to group or cluster the pin results using a ios map render?
I tried the following logic, but I got confused in the implementation.
https://github.com/xamarin/ios-samples/blob/main/ios11/MapKitSample/Tandm/ViewController.cs
if (e.NewElement != null)
{
var formsMap = (InitMap)e.NewElement;
var nativeMap = Control as MKMapView;
customPins = formsMap.InitCustomPins;
nativeMap.GetViewForAnnotation = GetViewForAnnotation;
nativeMap.CreateClusterAnnotation = GetClusterView();
}
[![protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
{
MKAnnotationView annotationView = null;
if (annotation is MKUserLocation)
return null;
var customPin = GetCustomPins(annotation as MKPointAnnotation);
//it returns 37 pins . I would like to cluster by item.Id .
if (customPin == null)
{
return null;
}
foreach (var item in customPin)
{
var clusterThis=item.id
if ID==1
{ PAINT THE BUBBLE RED }
int clusterSize = GetClusterSize(); // Obtain the cluster size
MKCreateClusterAnnotation clusterAnnotation =
GetClusterAnnotation(clusterSize); heres what I dont know how to implement .
}
}]
Upvotes: 0
Views: 167
Reputation: 7990
Map marker clustering is a new feature in iOS11. The sample MapKit Sample "Tandm" shows how to implement the new iOS 11 annotation clustering feature.
I made a demo following the New Features in MapKit on iOS 11 and use much code in MapKit Sample "Tandm" as well.
CustomMapRenderer.cs
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
//Some differences with the previous thread
//For performance reasons, I try adding pins natively
//instead of using data bindings.
AddPinData();
LoadDataForMapRegionAndBikes(nativeMap);
nativeMap.GetViewForAnnotation = GetViewForAnnotation;
}
After we add some pin data, we should add pin annotation to our nativeMap. In order to do it, We define a MyCustomPin model class.
private void LoadDataForMapRegionAndBikes(MKMapView nativeMap)
{
var pins = new List<MyCustomPin>();
foreach (PinData data in PinsCollection)
{
NSNumber Lat = data.PinPostion.Latitude;
NSNumber Lgn = data.PinPostion.Longitude;
var Id = data.PinId;
var Label = new NSString(data.PinLabel);
var Name = new NSString(data.PinName);
CLLocationCoordinate2D Coordinate = new CLLocationCoordinate2D(Lat.NFloatValue, Lgn.NFloatValue);
MyCustomPin myCustomPin = new MyCustomPin(Coordinate, Name);
myCustomPin.Lat = Lat;
myCustomPin.Lgn = Lgn;
myCustomPin.Id = Id;
myCustomPin.Label = Label;
myCustomPin.Name = Name;
pins.Add(myCustomPin);
}
nativeMap.AddAnnotations(pins.ToArray());
}
Here is MyCustomPin class. Later we will decide the clusteridendifier according this Id property.
public class MyCustomPin : MKPointAnnotation
{
public NSNumber Lat { get; set; }
public NSNumber Lgn { get; set; }
public int Id { get; set; }
public NSString Name { get; set; }
public NSString Label { get; set; }
#region Constructors
public MyCustomPin()
{
}
public MyCustomPin(CLLocationCoordinate2D cLLocationCoordinate2D,string title) : base(cLLocationCoordinate2D,title,title)
{
}
}
GetViewForAnnotation is the most important method, we customize our pin and cluster in it. CustomMKAnnotationView inherits from MKAnnotationView, which is the visual representation of custom Pin.
protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
{
if (annotation is MyCustomPin)
{
var marker = annotation as MyCustomPin;
var view = mapView.DequeueReusableAnnotation(marker.Name) as CustomMKAnnotationView;
if (view == null)
{
view = new CustomMKAnnotationView(marker, marker.Name);
if (marker.Id == 45)
{
view.Image = UIImage.FromFile("unicycle.png");
}
else if (marker.Id == 67)
{
view.Image = UIImage.FromFile("tricycle.png");
}
else
{
view.Image = UIImage.FromFile("pin.png");
}
}
view.CalloutOffset = new CGPoint(0, 0);
view.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
view.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
view.CanShowCallout = true;
return view;
}
else if (annotation is MKClusterAnnotation)
{
var cluster = annotation as MKClusterAnnotation;
var view = mapView.DequeueReusableAnnotation(MKMapViewDefault.ClusterAnnotationViewReuseIdentifier) as ClusterView;
if (view == null)
{
view = new ClusterView(cluster, MKMapViewDefault.ClusterAnnotationViewReuseIdentifier);
}
return view;
}
else if (annotation != null)
{
var unwrappedAnnotation = MKAnnotationWrapperExtensions.UnwrapClusterAnnotation(annotation);
return GetViewForAnnotation(mapView, unwrappedAnnotation);
}
return null;
}
CustomMKAnnotationView.cs
ClusteringIdentifier – This controls which markers get clustered together. For example, if the pin id is 45, we set all its annotation view's ClusteringIdentifier to the same value, such as 45. Then they will be clustered.
public class CustomMKAnnotationView : MKAnnotationView
{
public string Name { get; set; }
public string Url { get; set; }
#region Override Methods
public override IMKAnnotation Annotation
{
get
{
return base.Annotation;
}
set
{
base.Annotation = value;
var pin = value as MyCustomPin;
if (pin != null)
{
int id = pin.Id;
switch (id)
{
case 45:
DisplayPriority = MKFeatureDisplayPriority.DefaultHigh;
ClusteringIdentifier = "45";
break;
case 67:
DisplayPriority = MKFeatureDisplayPriority.DefaultHigh;
ClusteringIdentifier = "67";
break;
}
}
}
}
#endregion
public CustomMKAnnotationView(IMKAnnotation annotation, string id)
: base(annotation, id)
{
}
}
ClusterView.cs
This class uses for customize the cluster view. We count the number, paint different color for different cluster and draw the text in the circle.
public class ClusterView : MKAnnotationView
{
#region Static Variables
public static UIColor UnicycleColor = UIColor.FromRGB(254, 122, 36);
public static UIColor TricycleColor = UIColor.FromRGB(153, 180, 44);
#endregion
#region Computed Properties
public override IMKAnnotation Annotation
{
get
{
return base.Annotation;
}
set
{
base.Annotation = value;
// TODO: Workaround, the developer should be able to use
// `value as MKClusterAnnotation` instead of the following
// extension method call:
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) => {
var customPin = cluster.MemberAnnotations[0] as MyCustomPin;
if (customPin.Id == 45)
{
UnicycleColor.SetFill();
}
else
{
TricycleColor.SetFill();
}
UIBezierPath.FromOval(new CGRect(0, 0, 40, 40)).Fill();
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);
});
}
}
}
#endregion
#region Constructors
public ClusterView()
{
}
public ClusterView(NSCoder coder) : base(coder)
{
}
public ClusterView(IntPtr handle) : base(handle)
{
}
public ClusterView(IMKAnnotation annotation, string reuseIdentifier) : base(annotation, reuseIdentifier)
{
// Initialize
DisplayPriority = MKFeatureDisplayPriority.DefaultHigh;
CollisionMode = MKAnnotationViewCollisionMode.Circle;
// Offset center point to animate better with marker annotations
CenterOffset = new CoreGraphics.CGPoint(0, -10);
}
#endregion
}
Finally, this is the effect,
Upvotes: 0