Xamarin.forms Xamarin Forms CustomMapRenderer iOS

Xamarin.forms Xamarin Forms CustomMapRenderer iOS,xamarin.forms,Xamarin.forms,目前正在Android和iOS上的地图中使用自定义PIN,而在Android上使用自定义PIN时,我在iOS上的自定义渲染器下面的代码中遇到了一个空异常(完全自定义渲染器),我正在努力找出原因 CustomPin GetCustomPin(MKPointAnnotation annotation) { var position = new Position(annotation.Coordinate.Latitude, annotation.Coordinate.

目前正在Android和iOS上的地图中使用自定义PIN,而在Android上使用自定义PIN时,我在iOS上的自定义渲染器下面的代码中遇到了一个空异常(完全自定义渲染器),我正在努力找出原因

    CustomPin GetCustomPin(MKPointAnnotation annotation)
    {
        var position = new Position(annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
        foreach (var pin in customPins)
        {
            if (pin.Pin.Position == position)
            {
                return pin;
            }
        }
        return null;
    }
我已经从提供的Xamarin示例中复制了代码,该示例正确地应用了自定义pin

我的custommaprenderer:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace WorkingWithMaps.iOS
{
    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;
            }
        }

        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");
            }

            annotationView = mapView.DequeueReusableAnnotation(customPin.Id);
            if (annotationView == null)
            {
                annotationView = new CustomMKAnnotationView(annotation, customPin.Id);
                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).Id = customPin.Id;
                ((CustomMKAnnotationView)annotationView).Url = customPin.Url;
            }
            annotationView.CanShowCallout = true;

            return annotationView;
        }

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

        void OnDidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)
        {
            var customView = e.View as CustomMKAnnotationView;
            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.Pin.Position == position)
                {
                    return pin;
                }
            }
            return null;
        }
    }
}
[程序集:ExportRenderer(typeof(CustomMap)、typeof(CustomMapRenderer))]
命名空间使用maps.iOS工作
{
类CustomMapRenderer:MapRenderer
{
UIView-customPinView;
列出客户PIN码;
受保护的覆盖无效OnElementChanged(ElementChangedEventArgs e)
{
基础。一个要素发生变化(e);
if(e.OldElement!=null)
{
var nativeMap=作为MKMapView的控件;
nativeMap.GetViewForAnnotation=null;
nativeMap.CalloutAccessoryControlTapped-=OnCalloutAccessoryControlTapped;
nativeMap.DidSelectAnnotationView-=OnDidSelectAnnotationView;
nativeMap.DidDesceneAnnotationView-=OnDidDesceneAnnotationView;
}
if(例如NewElement!=null)
{
var formsMap=(CustomMap)e.NewElement;
var nativeMap=作为MKMapView的控件;
customPins=formsMap.customPins;
nativeMap.GetViewForAnnotation=GetViewForAnnotation;
nativeMap.CalloutAccessoryControlTapped+=OnCalloutAccessoryControlTapped;
nativeMap.DidSelectAnnotationView+=OnDidSelectAnnotationView;
nativeMap.DidDesceneAnnotationView+=OnDidDesceneAnnotationView;
}
}
MKAnnotationView GetViewForAnnotation(MKMapView地图视图、IMKAnnotation注释)
{
MKAnnotationView annotationView=null;
if(注释为MKUserLocation)
返回null;
var anno=注释为MKPointAnnotation;
var customPin=GetCustomPin(anno);
如果(customPin==null)
{
抛出新异常(“未找到自定义pin”);
}
annotationView=mapView.DequeueReusableAnnotation(customPin.Id);
if(annotationView==null)
{
annotationView=新的CustomMKAnnotationView(注释,customPin.Id);
annotationView.Image=UIImage.FromFile(“pin.png”);
annotationView.CalloutOffset=新的CGPoint(0,0);
annotationView.LeftCalloutAccessoryView=新的UIImageView(UIImage.FromFile(“monkey.png”);
annotationView.RightCalloutAccessoryView=UIButton.FromType(UIButtonType.DetailDisclosure);
((CustomMKAnnotationView)annotationView).Id=customPin.Id;
((CustomMKAnnotationView)annotationView.Url=customPin.Url;
}
annotationView.CanShowCallout=true;
返回注释视图;
}
一旦CalloutAccessoryControlTapped(对象发送方,mkMapViewAccessorTappedEventArgs e)无效
{
var customView=e.作为CustomMKAnnotationView查看;
如果(!string.IsNullOrWhiteSpace(customView.Url))
{
OpenUrl(新基金会NSUrl(CuffVIEW .URL));
}
}
void OnDidSelectAnnotationView(对象发送方,MKAnnotationViewEventArgs e)
{
var customView=e.作为CustomMKAnnotationView查看;
customPinView=新UIView();
if(customView.Id==“Xamarin”)
{
Frame=新的CGRect(0,0,200,84);
var image=新的UIImageView(新的CGRect(0,0,200,84));
image.image=UIImage.FromFile(“xamarin.png”);
customPinView.AddSubview(图像);
customPinView.Center=新的CGPoint(0,-(e.View.Frame.Height+75));
e、 View.AddSubview(customPinView);
}
}
void OnDidCancelAnnotationView(对象发送方,MKAnnotationViewEventArgs e)
{
如果(!e.View.Selected)
{
customPinView.RemoveFromSuperview();
customPinView.Dispose();
customPinView=null;
}
}
CustomPin GetCustomPin(MKPointAnnotation)
{
var位置=新位置(annotation.Coordinate.Latitude,annotation.Coordinate.Longitude);
foreach(customPins中的var pin)
{
if(pin.pin.Position==位置)
{
回位销;
}
}
返回null;
}
}
}

链接到我的存储库:

您的自定义pin缺少此处所需的ID:

annotationView = mapView.DequeueReusableAnnotation(customPin.Id);
需要:

也代替

 if (annotation is MKUserLocation)
                return null;

 var anno = annotation as MKPointAnnotation;
使用

因为注释可以是其他东西,如下面所示

此外,我还发现下面的代码(在此事件处理程序中使用MoveToRegion)对此渲染器产生了问题,因为GetViewForAnnotation开始接收除MKPointAnnotation之外的参数,但上面的强制转换保护使其免于崩溃。下面代码的另一个问题是,如果您的pin位置远离实际位置,您将看不到自定义pin,定位器跟踪器将始终将您的地图放入您的位置。在这种情况下,要调试pin位置,只需注释掉下面的“Move”行

maplocator.PositionChanged += (sender, e) =>
            {
                var position = e.Position;

                //map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(position.Latitude, position.Longitude), Distance.FromKilometers(2)));
            };
OnReverseGeocodeButtonClicked函数将很快崩溃:-),因为未分配类成员pin

warning CS0649: Field 'MainPage.pin' is never assigned to, and will always have its default value null

非常抱歉,错误的代码!当我发布这个问题的时候,我还没有完全清醒,不过现在已经解决了。感谢您的反馈。即使您做出了更改,每当pin进入视图时,我仍然会得到一个空引用。更具体地说,它现在声称我的customPin列表为空
maplocator.PositionChanged += (sender, e) =>
            {
                var position = e.Position;

                //map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(position.Latitude, position.Longitude), Distance.FromKilometers(2)));
            };
warning CS0649: Field 'MainPage.pin' is never assigned to, and will always have its default value null