Reputation: 563
XAML:
<local:CustomMap x:Name="mymap" MapType="Street" IsShowingUser="true"/>
Code:
var pin = new CustomPin ();
pin.MapPin.Label = "Test";
pin.MapPin.Position = new Position(32, 10);
pin.MapPin.Label = "1";
pin.MapPin.Address = "394 Pacific Ave, San Francisco CA";
pin.Id = "Xamarin";
pin = new CustomPin ();
pin.MapPin.Label = "Test2";
pin.MapPin.Position = new Position(33, 10);
pin.MapPin.Label = "2";
pin.MapPin.Address = "394 Pacific Ave, San Francisco CA";
pin.Id = "Xamarin";
mymap.CustomPins = new List<CustomPin> { pin };
mymap.Pins.Add (pin.MapPin);
With this code I only get one pin on the map and the pin is the latest one I created so in this case "Test2". How do I adjust the code so I can add multiple pins?
CustomMap:
public class CustomMap : Map
{
public MapContentType ContentType { get; set; }
public double CircleRadius { get; set; }
public List<Position> Positions { get; set; }
public List<CustomPin> CustomPins { get; set;}
public CustomCircle Circle { get; set; }
public CustomMap()
{
this.ContentType = MapContentType.Normal;
this.CircleRadius = 500;
this.Positions = new List<Position> ();
}
}
CustomPin:
public class CustomPin
{
public CustomPin() {
MapPin = new Pin();
}
public string Id { get; set; }
public EventHandler Url { get; set; }
public Pin MapPin { get; set; }
}
Custom renderer:
public class CustomMapRenderer : MapRenderer
{
MKPolylineRenderer polylineRenderer;
UIView customPinView;
List<CustomPin> customPins;
MKCircleRenderer circleRenderer;
protected override void OnElementChanged (ElementChangedEventArgs<View> e)
{
base.OnElementChanged (e);
if (e.OldElement != null) {
var nativeMap = Control as MKMapView;
nativeMap.OverlayRenderer = null;
nativeMap.GetViewForAnnotation = null;
nativeMap.GetViewForAnnotation = null;
nativeMap.DidSelectAnnotationView -= OnDidSelectAnnotationView;
nativeMap.DidDeselectAnnotationView -= OnDidDeselectAnnotationView;
}
if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
customPins = formsMap.CustomPins;
nativeMap.GetViewForAnnotation = GetViewForAnnotation;
nativeMap.GetViewForAnnotation = GetViewForAnnotation;
nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;
nativeMap.OverlayRenderer = GetOverlayRenderer;
CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[formsMap.Positions.Count];
int index = 0;
foreach (var position in formsMap.Positions) {
coords [index] = new CLLocationCoordinate2D (position.Latitude, position.Longitude);
index++;
}
var routeOverlay = MKPolyline.FromCoordinates (coords);
nativeMap.AddOverlay (routeOverlay);
}
}
MKOverlayRenderer GetOverlayRenderer (MKMapView mapView, IMKOverlay overlay)
{
if (polylineRenderer == null ) {
polylineRenderer = new MKPolylineRenderer (overlay as MKPolyline);
polylineRenderer.FillColor = UIColor.Blue;
polylineRenderer.StrokeColor = UIColor.Black;
polylineRenderer.LineWidth = 10;
polylineRenderer.Alpha = 0.4f;
}
return polylineRenderer;
}
string pId = "PinAnnotation";
MKAnnotationView GetViewForAnnotation (MKMapView mapView, IMKAnnotation annotation)
{
MKAnnotationView annotationView = null;
if (annotation is MKUserLocation)
return null;
var anno = annotation as MKPointAnnotation;
var customPin = GetCustomPin (anno);
if (customPin == null) {
throw new Exception ("Custom pin not found");
}
MKAnnotationView pinView = (MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);
annotationView = mapView.DequeueReusableAnnotation (customPin.Id);
if (annotationView == null) {
annotationView = new CustomMKPinAnnotationView (annotation, customPin.Id);
annotationView.Image = UIImage.FromFile ("pin.png");
//((MKPinAnnotationView)pinView).PinColor = MKPinAnnotationColor.Green;
annotationView.CalloutOffset = new CGPoint (0, 0);
annotationView.LeftCalloutAccessoryView = new UIImageView (UIImage.FromFile ("monkey.png"));
annotationView.RightCalloutAccessoryView = UIButton.FromType (UIButtonType.DetailDisclosure);
((CustomMKPinAnnotationView)annotationView).Id = customPin.Id;
((CustomMKPinAnnotationView)annotationView).Url = customPin.Url;
}
annotationView.CanShowCallout = true;
return annotationView;
}
void OnDidSelectAnnotationView (object sender, MKAnnotationViewEventArgs e)
{
var customView = e.View as CustomMKPinAnnotationView;
customPinView = new UIView ();
if (customView.Id == "Xamarin") {
customPinView.Frame = new CGRect (0, 0, 200, 84);
var image = new UIImageView (new CGRect (0, 0, 200, 84));
image.Image = UIImage.FromFile ("xamarin.png");
customPinView.AddSubview (image);
customPinView.Center = new CGPoint (0, -(e.View.Frame.Height + 75));
e.View.AddSubview (customPinView);
}
}
void OnDidDeselectAnnotationView (object sender, MKAnnotationViewEventArgs e)
{
if (!e.View.Selected) {
customPinView.RemoveFromSuperview ();
customPinView.Dispose ();
customPinView = null;
}
}
CustomPin GetCustomPin (MKPointAnnotation annotation)
{
var position = new Position (annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
foreach (var pin in customPins) {
if (pin.MapPin.Position == position) {
return pin;
}
}
return null;
}
}
}
Upvotes: 0
Views: 1435
Reputation: 43
I've had the same problem with the Xamarin Custom Map Renderer.
I found the cause of the problem was the check for mapOverlay == null
in the OnMapElementClick
function.
Comment this out, and everything works now for multiple pins. Not sure why this was there in the first place.
Upvotes: 0
Reputation: 1197
you are getting one pin , because you are adding one pin . you need to know some basics of programming "like changing the properties of an object doesn't create new object "
try this
var pin = new CustomPin ();
pin.MapPin.Label = "Test";
pin.MapPin.Position = new Position(32, 10);
pin.MapPin.Label = "1";
pin.MapPin.Address = "394 Pacific Ave, San Francisco CA";
pin.Id = "Xamarin";
var pin1 = new CustomPin ();
pin1.MapPin.Label = "Test2";
pin1.MapPin.Position = new Position(33, 10);
pin1.MapPin.Label = "2";
pin1.MapPin.Address = "394 Pacific Ave, San Francisco CA";
pin1.Id = "Xamarin";
mymap.CustomPins = new List<CustomPin> { pin,pin1 };
mymap.Pins.Add (pin.MapPin);
mymap.Pins.Add (pin1.MapPin);
solution to your problem mentioned in comments,App.Items is a list getting populated from database or webservice(in my case web service) `using
System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using System;
namespace App
{
public class MapPage : ContentPage
{
public CustomMap customMap1{ get; set;}
public MapPage ()
{
Title ="Stores";
Icon = "flag_map_marker4.png";
var customMap = new CustomMap {
MapType = MapType.Street,
WidthRequest = App.ScreenWidth,
HeightRequest = App.ScreenHeight
};
customMap.CustomPins = new List<CustomPin>();
if (App.Items != null && App.Items.Count > 0) {
foreach (var t in App.Items) {
var temp = new CustomPin () {
Pin = new Pin () {
Label = t.Name,
Type = PinType.Place,
Position = new Position (t.Lat, t.Lon),
Address = t.Address1
},
Url = t.Link
};
customMap.CustomPins.Add (temp);
}
foreach (var pin in customMap.CustomPins) {
customMap.Pins.Add (pin.Pin);
}
// dont delete below code ,they will save you if timer doesnt work .
//var temp1 = new MapSpan(customMap.CustomPins [0].Pin.Position,
// if(Device.OS == TargetPlatform.iOS)
// customMap.MoveToRegion (MapSpan.FromCenterAndRadius (customMap.CustomPins [0].Pin.Position, Distance.FromMiles (0.20)));
if(Device.OS == TargetPlatform.Android)
customMap.MoveToRegion (MapSpan.FromCenterAndRadius (customMap.CustomPins [0].Pin.Position, Distance.FromMiles (55.0)));
if (Device.OS == TargetPlatform.iOS) {
Device.StartTimer (TimeSpan.FromMilliseconds (500), () => {
customMap.MoveToRegion (MapSpan.FromCenterAndRadius (customMap.CustomPins [0].Pin.Position, Distance.FromMiles (55.0)));
return false;
});
}
}
Content = customMap;
}
}
}
` Just ignore the lines which doesn't concern you !
Upvotes: 1