iosxamarin.formsmapsmkannotationview

xamarin forms CustomPin ios Render


can't get to display all the pins in the following list to the view. NOTE: my sample below is not part of the xamarin forms documentation . it was my idea that maybe I could combine both lists and display in the map at the same time.

  1. pin.id==1 (main pin )constant changes its position , trying to add a different image or color
  2. on loading the map Im trying to display 9 more pins(static-aditional pins ) these ones , wont move. again I assigned a different color of image. Results, one list overwrites the other one .so either I display pin 1 or the other 9 pins . but I cant put the 10 pins in the screen at the same time.

Heres how to create the first static list and the single pin

  public class CustomMap : Map
        {
            public List<CustomPin> AdditionalPins { get; set; }
            public List<CustomPin> CustomPins { get; set; }
           
       
    public CustomMap()
    {
       
        CustomPins = new List<CustomPin>();
        
        AdditionalPins = new List<CustomPin>();
    }

on the mainpage : both of the pins lists

var customPin = new CustomPin
                                {
                                    PinId = 1,
                                    // Position = new Position(37.7749, -122.4194), // Set the position of the pin
                                    Label = "Custom Pin",
                                    Address = "Custom Address",
                                    Rotation = -45 // Set the rotation angle in degrees
                                };
                                Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
                                {
                                    customPin.Position = pos;
                                    // pins.Position = pos;
        
                                    if (myMap.Pins.Count == 0)
                                    {
                                        
                                        myMap.Pins.Add(customPin);
                                    
                                    }....

2.set of static pins

     foreach (var coordinate in coordinates)
                    {
                        var poss = new Position(coordinate.Latitude, coordinate.Longitude);
                        CustomPin additionalPin = new CustomPin
                        {
                            PinId = 20,
                            Label = "Additional Pin",
                            Name = coordinate.StopNumber
                            // Add more properties as needed
                        };
    
                        myMap.AdditionalPins.Add(additionalPin);

Now, I do get both of the lists one have 1 pin that its updating its position every 10 seconds and the other one (adittionalpins =9 set of coordinates) Here , combine both of the list

   private List<CustomPin> GetAllPins(MKPointAnnotation mKPointAnnotation)
        {
            List<CustomPin> matchingPins = new List<CustomPin>();

            if (mKPointAnnotation != null)
            {
                var position = new Position(mKPointAnnotation.Coordinate.Latitude, mKPointAnnotation.Coordinate.Longitude);


                // Check Pins collection
                foreach (var pin in ((CustomMap)Element).Pins)
                {
                   
                        matchingPins.Add(pin as CustomPin);
                        // If a match is found in Pins, no need to check AdditionalPins, break out of the loop
                       
                    
                }

              //  Check AdditionalPins collection only if a match is not found in Pins


                    foreach (var additionalPin in ((CustomMap)Element).AdditionalPins)
                {

                    matchingPins.Add(additionalPin);
                    // If a match is found in AdditionalPins, no need to continue the loop



                }

            }

            return matchingPins;
        }

protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
        {
            if (annotation is MKUserLocation)
                return null;
         

            var result = GetAllPins(annotation as MKPointAnnotation); //HERE -- get all the items 
            if (result != null)
            {
                
                List<CustomPin> pins = result;

                if (pins != null && pins.Any())
                {
                    
                    foreach (var D in pins)
                    {
                          if (annotationView == null)
                         {
                         annotationView = new MKAnnotationView(annotation, reuseIdentifier);

                            if (D.PinId == 1) //it gets here the first time 
                            {
                                annotationView.Image = UIImage.FromFile("lilocation.png");
                              
                            }
                            else if (D.PinId == 20) //never assign this part to the view 
                            {
                                annotationView.Image = UIImage.FromFile("red.png");
                            }

                           
                        }
                       
                    }
                }

                    return annotationView;
                
            }

Goal, is to display every single item in the list with its image and behavior . THE ISSUE is the view only gets null the first time.


Solution

  • I prefer using MVVM pattern to display a collection of Pins on Maps.

    You may use data bindings to display pins. You could refer to this: Display a pin collection.

    Here is my little demo. All data we needed is set in MainPageViewModel.

    <local:CustomMap x:Name="customMap" ItemsSource="{Binding PinsCollection}"
                     MapType="Street">
        <local:CustomMap.ItemTemplate>
            <DataTemplate x:DataType="local:PinData" >
                <local:CustomPin PinId="{Binding PinId}" Name="{Binding PinName}"
                                 Label="{Binding PinLabel}"
                                 Position="{Binding PinPostion}"/>
            </DataTemplate>
        </local:CustomMap.ItemTemplate>
    </local:CustomMap>
    

    So, you may add some BindableProperties for your CustomPin, such as PinId or others.

    public class CustomPin : Pin
    {
    
        public static readonly BindableProperty PinIdProperty =BindableProperty.Create("PinId", typeof(int), typeof(CustomPin), null);
    
        public int PinId
        {
            get { return (int)GetValue(PinIdProperty); }
            set { SetValue(PinIdProperty, value); }
        }
    

    One of the differences between your design and mine is that I don't want to create separate collections for custom pins and static pins. I want to combine them because actually we could identify them using PinId or other properties.

    In our ViewModel, I just create one collection,

    public class MainPageViewModel
    {
        public ObservableCollection<PinData> PinsCollection { get; set; } = new ObservableCollection<PinData>();
    
        //Add some test data
        public MainPageViewModel()
        {
            PinsCollection.Add(
                new PinData()
                {
                    PinId = 0,
                    PinName = "CustomPin",
                    PinPostion = new Position(37.79752, -122.40183),
                    PinLabel = "CustomPin"
                });
    
            PinsCollection.Add(
                new PinData()
                {
                    PinId = 1,
                    PinName = "AddtionalPin1",
                    PinPostion = new Position(37.80252, -122.40183),
                    PinLabel = "AddtionalPin1"
                });
            ...
    

    Notice that PinData class here is the Model class. I added some Properties in it. And it's better to implement INotifyPropertyChanged. Then the UI control could change due to the data changes.

    public class PinData : INotifyPropertyChanged
    {
    
        public string PinName { get; set; }
    
        public int PinId { get; set; }
    
        public string PinLabel { get; set; }
    
        public string PinAddress { get; set; }
    
        private Position pinPostition;
        public Position PinPostion
        {
            get
            {
                return pinPostition;
    
            }
            set
            {
                pinPostition = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PinPostion)));
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    }
    

    The above is all for Froms project. Then we may also make some changes for Custom Renderer.

    For example, we could set different images for static or custom pins based on the PinId.

    In CustomMapRenderer

    if (annotationView == null)
    {
       annotationView = new CustomMKAnnotationView(annotation, customPin.Name);
    
       if (customPin.PinId == 0)
       {
           annotationView.Image = UIImage.FromFile("monkey.png");
    
       }
       else
       {
           annotationView.Image = UIImage.FromFile("pin.png");
       }
    

    Okay, it just a small demo to show my idea about your case. And this is the effect. You may see four static purple pins (not move). A small monkey (custom pin) will move towards left bottom corner several seconds a time. Is this the effect you want? Please let me know if you have any questions.

    enter image description here