设置自定义标记图像将覆盖默认标记图标和自定义图标

Setting custom marker image would overlay default marker icon along with custom icon

将表单版本更新到 2.4.0.282 后,我开始在 MapView 中遇到这种奇怪的行为。我在 android 中为地图创建了一个自定义渲染器,我根据自己的要求在其中设置标记图像。自定义标记实际上出现了,但在它上面,它的默认图标仍然被覆盖。

请注意,我使用的是 Xamarin.Maps 版本 2.4.0.282,我也尝试过降级到以前的版本,但没有任何帮助。

我什至通过评论行试过了,

Forms.SetFlags("FastRenderers_Experimental");

但即使这样也无济于事。

下面是我创建的渲染器,

public class CustomMapRenderer : MapRenderer, IOnMapReadyCallback
    {
        GoogleMap map;

        public static double PreviousDistance = 0;

        List<CustomPin> customPins;

        CustomMap formsMap = null;

        protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                map.InfoWindowClick -= OnInfoWindowClick;
                map.MarkerClick -= OnMarkerClick;
            }

            if (e.NewElement != null)
            {
                formsMap = (CustomMap)e.NewElement;
                customPins = formsMap.CustomPins;
                ((MapView)Control).GetMapAsync(this);
            }
        }

        protected override void OnMapReady(GoogleMap googleMap)
        {
            map = googleMap;
            map.InfoWindowClick += OnInfoWindowClick;

            map.MarkerClick += OnMarkerClick;

            map.UiSettings.ZoomControlsEnabled = false;

            formsMap.MoveToRegion(MapSpan.FromCenterAndRadius(formsMap.Location, Distance.FromMiles(1.0)));

            if(customPins != null && customPins.Count > 0)
            {
                setMapPins("CustomPins");
            }
        }

        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == "CustomPins" || (e.PropertyName.Equals("VisibleRegion")))
            {
                setMapPins(e.PropertyName);
            }
        }

        private void setMapPins(string PropertyName)
        {
            customPins = formsMap.CustomPins;

            map.Clear();

            if (customPins != null && customPins.Count > 0)
            {
                if (PropertyName == "CustomPins")
                {
                    //Set map zoom
                    var defaultZoom = 14;

                    try
                    {
                        PreviousDistance = DistanceCalculation.MoveToRegionData.MoveToRegion(formsMap, customPins, defaultZoom, PreviousDistance);
                    }
                    catch (Exception ex)
                    {
                        PreviousDistance = 0;
                        Console.WriteLine(ex.Message);
                    }
                }

                foreach (var pin in customPins)
                {
                    var pinImage = Resources.GetIdentifier(pin.PinImage.ToLower(), "drawable", Context.PackageName);
                    var markerImg = BitmapDescriptorFactory.FromResource(pinImage);

                    map.AddMarker(new MarkerOptions().SetTitle(pin.Pin.Label).SetSnippet(pin.Id).SetPosition(new LatLng(pin.Pin.Position.Latitude, pin.Pin.Position.Longitude)).SetIcon(markerImg));
                }
            }
            else
            {
                Console.WriteLine("In else!!");
            }
        }

        protected override void OnLayout(bool changed, int l, int t, int r, int b)
        {
            base.OnLayout(changed, l, t, r, b);

            if (changed)
            {
            }
        }

        void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
        {
            var customPin = GetCustomPin(e.Marker);
            if (customPin == null)
            {
                throw new Exception("Custom pin not found");
            }

            if (!string.IsNullOrWhiteSpace(customPin.Url))
            {
                var url = global::Android.Net.Uri.Parse(customPin.Url);
                var intent = new Intent(Intent.ActionView, url);
                intent.AddFlags(ActivityFlags.NewTask);
                global::Android.App.Application.Context.StartActivity(intent);
            }
        }

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

        void OnMarkerClick(object sender, GoogleMap.MarkerClickEventArgs ea)
        {   
            var marker = (Marker) ea.Marker;
            formsMap.IsPinClicked = false;

            var customPin = GetCustomPin(marker);
            if (customPin == null)
            {
                throw new Exception("Custom pin not found");
            }
            formsMap.SelectedPinId = Convert.ToInt32(marker.Snippet);
            formsMap.IsPinClicked = true;
        }
    }

这是现在的样子..

I have created a custom renderer for map in android where I am setting marker images as per my requirement. Custom markers in fact appear, but on top of it, it's default icon still gets overlaid.

我做了一个演示并重现了这个问题,经过一些测试我发现覆盖OnMapReady函数导致了这个问题。即使完全为空 OnMapReady 也会出现问题。我的猜测是在自定义地图渲染中调用 OnMapReady 可能会导致重新渲染地图,包括图钉。

解法:

  1. 评论OnMapReady出来。
  2. OnMapReady中的逻辑移动到OnElementChanged
  3. 让您的局部变量 map=NativeMap 并确保 setMapPinsOnElementPropertyChanged 中被调用。

OnElementPropertyChanged 中添加 NativeMap.Clear(); 然后重试。希望对你有帮助!!!

查看下面用于在 Android 平台上自定义 pin 的代码。

[assembly:ExportRenderer (typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.Droid
{
    public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter
    {
        List<CustomPin> customPins;
        bool isDrawn;

        protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<View> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                NativeMap.InfoWindowClick -= OnInfoWindowClick;
            }

            if (e.NewElement != null)
            {
                var formsMap = (CustomMap)e.NewElement;
                customPins = formsMap.CustomPins;
                ((MapView)Control).GetMapAsync(this);
            }
        }


        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName.Equals("VisibleRegion") && !isDrawn)
            {
                NativeMap.Clear();
                NativeMap.InfoWindowClick += OnInfoWindowClick;
                NativeMap.SetInfoWindowAdapter(this);

                foreach (var pin in customPins)
                {
                    var marker = new MarkerOptions();
                    marker.SetPosition(new LatLng(pin.Pin.Position.Latitude, pin.Pin.Position.Longitude));
                    marker.SetTitle(pin.Pin.Label);
                    marker.SetSnippet(pin.Pin.Address);
                    marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));

                    NativeMap.AddMarker(marker);
                }
                isDrawn = true;
            }
        }
    }

}

更多详情Click here