question

Nort-0044 avatar image
0 Votes"
Nort-0044 asked RobCaplan edited

Xamarin.Forms iOS Customizing a Map Pin

When i add two or more pins, i have exaption: "[0:] An error occurred: 'Object reference not set to an instance of an object.'. Callstack: ' at TestApp.iOS.CustomMapRenderer.GetCustomPin (MapKit.MKPointAnnotation annotation) [0x0001f] in C:\Users\Admin\source\repos\TestApp\TestApp\TestApp.iOS\CustomMapRenderer.cs:114 "

Code when create exaption:

CustomPin GetCustomPin(MKPointAnnotation annotation)
            {
                var position = new Position(annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
                foreach (var pin in customPins)
                {
                    if (pin.Position == position)
                    {
                        return pin;
                    }
                }
                return null;
            }


My code, when i add pins:

public MapPage()
                {
                    InitializeComponent();
        
                    CustomPin pin = new CustomPin
                    {
                        Type = PinType.Place,
                        Position = new Position(37.79752, -122.40183),
                        Label = "Xamarin San Francisco Office",
                        Address = "394 Pacific Ave, San Francisco CA",
                        Name = "Xamarin",
                        Url = "http://xamarin.com/about/"
                    };
                    CustomPin pin2 = new CustomPin
                    {
                        Type = PinType.Place,
                        Position = new Position(40.79752, -122.40183),
                        Label = "Xamarin San Francisco Office",
                        Address = "394 Pacific Ave, San Francisco CA",
                        Name = "Xamarin",
                        Url = "http://xamarin.com/about/"
                    };
                    customMap.CustomPins = new List<CustomPin> { pin, pin2 };
                    customMap.Pins.Add(pin);
                    customMap.Pins.Add(pin2);
    
                    customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
                }
dotnet-csharpdotnet-xamarin
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Where are you initializing the customPins list in your renderer?

0 Votes 0 ·
     var customPin = GetCustomPin(annotation as MKPointAnnotation);

0 Votes 0 ·

Where is the customPins list you are trying to iterate through inside of that method created?

 foreach (var pin in customPins) // <-- THIS customPins
0 Votes 0 ·
 var formsMap = (CustomMap)e.NewElement;
                 var nativeMap = Control as MKMapView;
                 customPins = formsMap.CustomPins;

0 Votes 0 ·

1 Answer

LeonLu-MSFT avatar image
0 Votes"
LeonLu-MSFT answered LeonLu-MSFT edited

Hello,​

Welcome to our Microsoft Q&A platform!

If you want to custom renderer for maps' pin, you can download this demo for testing.

https://github.com/xamarin/xamarin-forms-samples/tree/main/CustomRenderers/Map

I add two pins in the map of iOS. It worked as normal.

94748-image.png

Here is custom renderer code for pins in iOS.

using System;
using System.Collections.Generic;
using CoreGraphics;
using CustomRenderer;
using CustomRenderer.iOS;
using MapKit;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.iOS;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.iOS
{
    public class CustomMapRenderer : MapRenderer
    {
        UIView customPinView;
        List<CustomPin> customPins;

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

            if (e.OldElement != null)
            {
                var nativeMap = Control as MKMapView;
                nativeMap.GetViewForAnnotation = null;
                nativeMap.CalloutAccessoryControlTapped -= OnCalloutAccessoryControlTapped;
                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.CalloutAccessoryControlTapped += OnCalloutAccessoryControlTapped;
                nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
                nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;
            }
        }

        protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
        {
            MKAnnotationView annotationView = null;

            if (annotation is MKUserLocation)
                return null;

            var customPin = GetCustomPin(annotation as MKPointAnnotation);
            if (customPin == null)
            {
                throw new Exception("Custom pin not found");
            }

            annotationView = mapView.DequeueReusableAnnotation(customPin.Name);
            if (annotationView == null)
            {
                annotationView = new CustomMKAnnotationView(annotation, customPin.Name);
                annotationView.Image = UIImage.FromFile("pin.png");
                annotationView.CalloutOffset = new CGPoint(0, 0);
                annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
                annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
                ((CustomMKAnnotationView)annotationView).Name = customPin.Name;
                ((CustomMKAnnotationView)annotationView).Url = customPin.Url;
            }
            annotationView.CanShowCallout = true;

            return annotationView;
        }

        void OnCalloutAccessoryControlTapped(object sender, MKMapViewAccessoryTappedEventArgs e)
        {
            CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
            if (!string.IsNullOrWhiteSpace(customView.Url))
            {
                UIApplication.SharedApplication.OpenUrl(new Foundation.NSUrl(customView.Url));
            }
        }

        void OnDidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)
        {
            CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
            customPinView = new UIView();

            if (customView.Name.Equals("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.Position == position)
                {
                    return pin;
                }
            }
            return null;
        }
    }
}

public class CustomMKAnnotationView : MKAnnotationView
    {
        public string Name { get; set; }

        public string Url { get; set; }

        public CustomMKAnnotationView(IMKAnnotation annotation, string id)
            : base(annotation, id)
        {
        }
    }



Best Regards,

Leon Lu



If the response is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



image.png (443.2 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks!
I'm using the example, and it work is strange.
I fixed that problem, but i have a new problem with this exception.

When i do max zoom and open again the map as FlyoutPage i have exception.
Video


0 Votes 0 ·

If this issue is solved, and you have another issue, you can open a new thread for it, in this way, it will make answer searching in the forum easier and be beneficial to other community members as well.

1 Vote 1 ·