Kettan Sinha
Kettan Sinha

Reputation: 25

Show two annotation on Xamarin iOS Map simultaneously

I know, Since I joined StackOver Flow, I am asking regular question, but understand me I in such circumstances where I could get any work around of my issues.

I have situation where On Current Lat-Long I want to annotate Car Image/Icon and pervious Lat-Long I want to annotate Moving Forward Arrow Icon. But I not getting any work around to do so in Xamarin iOS Map. This is the example

exact issue elaborate through image exact issue elaborate through image

I have created custom Map render as well.

public class CustomMapRenderer : MapRenderer
{
    private CustomMap _formsMap;

    public MKMapView ExtMap { get; private set; }

   
    List<CustomPin> customPins;
    UIView customPinView;
    protected override void OnElementChanged(ElementChangedEventArgs<View> e)
    {
        base.OnElementChanged(e);
        try
        {
            if (e.OldElement != null)
            {
                //var nativeMap = Control as MKMapView;
                 MKMapView nativeMap = new MKMapView();
                if (nativeMap != null)
                {
                    
                    nativeMap.RemoveAnnotations(nativeMap.Annotations);
                    nativeMap.GetViewForAnnotation = null;
                    nativeMap.DidSelectAnnotationView -= NativeMap_DidSelectAnnotationView;
                    nativeMap.DidDeselectAnnotationView -= NativeMap_DidDeselectAnnotationView;
                }
            }
            if (e.NewElement != null)
            {
                _formsMap = (ReplayMap)e.NewElement;
                var nativeMap = Control as MKMapView;
                ExtMap = Control as MKMapView;
                customPins = _formsMap.CustomPins;
                nativeMap.GetViewForAnnotation = GetViewForAnnotation;
                nativeMap.DidSelectAnnotationView += NativeMap_DidSelectAnnotationView;
                nativeMap.DidDeselectAnnotationView += NativeMap_DidDeselectAnnotationView;

            }
        }
        catch (Exception ex)
        {
            LogManager.Log(ex);
        }
    }
    private void NativeMap_DidDeselectAnnotationView(object sender, MKAnnotationViewEventArgs e)
    {
        if (!e.View.Selected)
        {
            customPinView.RemoveFromSuperview();
            customPinView.Dispose();
            customPinView = null;
        }
    }
    private void NativeMap_DidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)
    {
        try
        {
            var customView = e.View as CustomMKAnnotationView;
            customPinView = new UIView();
            var customPin = GetCustomPin(e.View.Annotation as MKPointAnnotation);
            if (customPin == null)
            {
                throw new Exception("Custom pin not found");
            }
            double lat = customView.Annotation.Coordinate.Latitude;
            double lon = customView.Annotation.Coordinate.Longitude;
            configureDetailView(customView, customPin);
        }
        catch (Exception ex)
        {
            LogManager.Log(ex);
        }
    }
    CustomPin GetCustomPin(MKPointAnnotation annotation)
    {
        var position = new Xamarin.Forms.Maps.Position(annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
        CustomPin pin = new CustomPin();
        try
        {
            if (customPins.Count > 0)
            {

                //Position Position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
                pin = customPins.Where(x => x.Position == position).FirstOrDefault();
                if (pin == null)
                {
                    pin = customPins[0];
                }
                return pin;
                //foreach (var pin in customPins)
                //{
                //    if ((pin.Position.Latitude == position.Latitude) & (pin.Position.Longitude == position.Longitude))
                //    {
                //        return pin;
                //    }
                //}
            }
            else
            {
                pin = customPins[0];
                return pin;
            }
        }
        catch (Exception ex)
        {

        }
        return pin;
        //if (Utility.customPins.Count > 1)
        //{
        //    foreach (var pin in Utility.customPins)
        //    {
        //        if (pin.Position == position)
        //        {
        //            return pin;
        //        }
        //    }
        //}
        //else
        //{
        //    return Utility.customPins[0];
        //}
        //return null;
    }
    void configureDetailView(MKAnnotationView annotationView, CustomPin pin)
    {
        int width = 150;
        int height = 100;
        var snapshotView = new UIView();
        snapshotView.BackgroundColor = UIColor.White;
        snapshotView.TranslatesAutoresizingMaskIntoConstraints = false;
        NSDictionary views = NSDictionary.FromObjectAndKey(snapshotView, new NSString("snapshotView"));
        snapshotView.AddConstraints(NSLayoutConstraint.FromVisualFormat("H:[snapshotView(175)]", new NSLayoutFormatOptions(), null, views));
        snapshotView.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:[snapshotView(150)]", new NSLayoutFormatOptions(), null, views));
        var options = new MKMapSnapshotOptions();
        options.Size = new CGSize(width, height);
        //options.MapType = MKMapType.SatelliteFlyover;
        // options.Camera = MKMapCamera.CameraLookingAtCenterCoordinate(annotationView.Annotation.Coordinate, 250, 65, 0);
        var snapshotter = new MKMapSnapshotter(options);
        snapshotter.Start((snapshot, error) =>
        {
            if (snapshot != null)
            {
                UIView markerInfoBackground = new UIView();
                markerInfoBackground.BackgroundColor = UIColor.White;
                // markerInfoBackground.Layer.ShadowColor = UIColor.Black;
                // markerInfoBackground.Layer.ShadowOpacity = 1.5f;
                // markerInfoBackground.Layer.ShadowRadius = 1.8f;
                markerInfoBackground.Layer.ShadowOffset = new SizeF(0.5f, 0.5f);
             
                markerInfoBackground.Add(imgLocation);
                UILabel lblLocation = new UILabel(new RectangleF(25, 90, width, 30));
                lblLocation.Text = getMapLocation(pin.Position.Latitude.ToString(), pin.Position.Longitude.ToString());
                lblLocation.Font = UIFont.SystemFontOfSize(12.0F);
                lblLocation.TextColor = UIColor.Gray;
                lblLocation.LineBreakMode = UILineBreakMode.WordWrap;
                lblLocation.Lines = 0;
                markerInfoBackground.Add(lblLocation);
                snapshotView.AddSubview(markerInfoBackground);
            }
        });
        annotationView.DetailCalloutAccessoryView = snapshotView;
    }
    public string getMapLocation(string lat, string lng)
    {
        string baseUri = "KEY";
        string location = "N/A";
        string requestUri = string.Format(baseUri, lat, lng);
        try
        {
            using (WebClient wc = new WebClient())
            {
                string result = wc.DownloadString(requestUri);
                var xmlElm = XElement.Parse(result);
                var status = (from elm in xmlElm.Descendants()
                              where
                                  elm.Name == "status"
                              select elm).FirstOrDefault();
                if (status.Value.ToLower() == "ok")
                {
                    var res = (from elm in xmlElm.Descendants()
                               where
                                   elm.Name == "formatted_address"
                               select elm).FirstOrDefault();
                    requestUri = res.Value;
                    location = res.Value;
                }
            }
        }
        catch (Exception) { }
        return location;
    }


    protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
    {

        MKAnnotationView annotationView = null;
        MKAnnotationView annotationView1 = new MKAnnotationView();
        try
        {
            if (annotation is MKUserLocation)
                return null;
            var customPin = GetCustomPin(annotation as MKPointAnnotation);
            if (customPin == null)
            {
                throw new Exception("Custom pin not found");
            }
            CustomPin CustPin = new CustomPin();

            if (annotationView == null)
            {
                annotationView = new CustomMKAnnotationView(annotation, customPin.ToString());
                annotationView1 = new CustomMKAnnotationView(annotation, customPin.ToString());

                OSAppTheme currentTheme = Xamarin.Forms.Application.Current.RequestedTheme;

                foreach (CustomPin item in _formsMap.Pins)
                {

                    var radians = item.Rotation + 90;
                    if (currentTheme == OSAppTheme.Dark)
                    {
                        annotationView.Image = RotateImage(UIImage.FromFile("car_icon_3.png"), Convert.ToSingle(radians));
                        annotationView1.Image = RotateImage(UIImage.FromFile("darkMode.png"), Convert.ToSingle(radians));
                    }
                    
                    else
                    {
                        annotationView.Image = RotateImage(UIImage.FromFile("car_icon_1.png"), Convert.ToSingle(radians));
                        annotationView1.Image = RotateImage(UIImage.FromFile("Moving.png"), Convert.ToSingle(radians));
                    }
                }
            }
            annotationView.CanShowCallout = true;
        }
        catch (Exception ex)
        {
            LogManager.Log(ex);
        }
        return annotationView;
    }

    public UIImage RotateImage(UIImage image, float degree)
    {
        float Radians = degree * (float)Math.PI / 180;
        UIView view = new UIView(frame: new CGRect(0, 0, image.Size.Width, image.Size.Height));
        CGAffineTransform t = CGAffineTransform.MakeRotation(Radians);
        view.Transform = t;
        CGSize size = view.Frame.Size;
        UIGraphics.BeginImageContext(size);
        CGContext context = UIGraphics.GetCurrentContext();
        context.TranslateCTM(size.Width / 2, size.Height / 2);
        context.RotateCTM(Radians);
        context.ScaleCTM(1, -1);
        context.DrawImage(new CGRect(-image.Size.Width / 2, -image.Size.Height / 2, image.Size.Width, image.Size.Height), image.CGImage);
        UIImage imageCopy = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();
        return imageCopy;
    }
}

Android Custom Renderer Code. Basically what we have done created two object of MarkerOptions. marker and marker2 in Customrenderer and on both markers we have used different images and Assigned one marker to the Google Maps Property.

using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Widget;
using CustomRenderer.Droid;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Xml.Linq;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
[assembly: ExportRenderer(typeof(ReplayMap), typeof(ReplayCustomRenderer))]
namespace CustomRenderer.Droid
{
    [Xamarin.Forms.Internals.Preserve(AllMembers = true)]
    public class ReplayCustomRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter
    {

        CustomPin customPin;
        List<CustomPin> customPins;
        public new Android.Gms.Maps.GoogleMap Map { get; set; }

        [Obsolete]
        public ReplayCustomRenderer()
        {
        }
        protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement != null)
            {
                NativeMap.InfoWindowClick -= OnInfoWindowClick;
                Map.InfoWindowClick -= OnInfoWindowClick;
            }
            if (e.NewElement != null)
            {
                var formsMap = (ReplayMap)e.NewElement;
                
                customPins = formsMap.CustomPins;
            }
        }
        protected override void OnMapReady(GoogleMap map)
        {
            Map = map;
            base.OnMapReady(map);
            MessagingCenter.Subscribe<Page>(this, "Clear", (value) =>
            {
                try
                {
                    //Map = map;
                    //base.OnMapReady(map);
                    Map.Clear();
                }
                catch (Exception ex)
                {

                }
            });
            map.MyLocationEnabled = false;
            NativeMap.InfoWindowClick += OnInfoWindowClick;
            NativeMap.SetInfoWindowAdapter(this);
            Map.MarkerClick += Map_MarkerClick;
        }

        private void Map_MarkerClick(object sender, GoogleMap.MarkerClickEventArgs e)
        {
            GetInfoContents(e.Marker);
            e.Marker.ShowInfoWindow();
        }

        protected override MarkerOptions CreateMarker(Pin pin)
        {
            MarkerOptions marker = new MarkerOptions();
            MarkerOptions marker2 = new MarkerOptions();

            try
            {
                marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
                marker.SetTitle(pin.Label);
                marker.SetSnippet(pin.Address);
                marker2.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
                marker2.SetTitle(pin.Label);
                marker2.SetSnippet(pin.Address);
                CustomPin CustPin = new CustomPin();
                CustPin = (CustomPin)pin;
                marker.SetRotation(CustPin.Rotation + 90);
                marker2.SetRotation(CustPin.Rotation + 180);
                OSAppTheme currentTheme = Xamarin.Forms.Application.Current.RequestedTheme;
                
                 marker.SetIcon(BitmapDescriptorFactory.FromAsset("car_icon_1.png"));
                 marker2.SetIcon(BitmapDescriptorFactory.FromAsset("Moving.png"));
                
               
                Map.AddMarker(marker2);


            }
            catch (Exception ex)
            {
                LogManager.Log(ex);
            }
            return marker;
        }
    }
}

Upvotes: 0

Views: 330

Answers (1)

ColeX
ColeX

Reputation: 14475

You can add the pin twice with the same location in Froms project.

And add a extra property to distinguish the pin type and set different icons accordingly .

public class CustomPin : Pin
{
    public string PinType { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
}


CustomPin pin1 = new CustomPin
    {
        PinType = "1",
        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
    {
        PinType = "2",
        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/"
    };

customMap.CustomPins = new List<CustomPin> { pin1,pin2 };
customMap.Pins.Add(pin1);
customMap.Pins.Add(pin2);

iOS project


//GetViewForAnnotation

string image1 = (customPin.PinType == "1")?"car_icon_1.png":"Moving.png";
annotationView.Image = RotateImage(UIImage.FromFile(image1), Convert.ToSingle(radians));

Upvotes: 0

Related Questions