2017-06-28 22 views
0

Momentan arbeiten Sie daran, benutzerdefinierte Pins in Karten sowohl auf Android als auch iOS zu verwenden, während sie gerade auf Android läuft. Ich erhalte eine Null-Ausnahme im Code direkt darunter (vollständiger benutzerdefinierter Renderer weiter unten) Custom Renderer auf iOS und ich kämpfe um herauszufinden, was es verursacht.Xamarin Forms CustomMapRenderer 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; 
    } 

Ich habe den Code aus der Xamarin Probe bei https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/map/customized-pin/ und die Probe trifft Stift richtig den benutzerdefinierten vorgesehen kopiert.

Mein 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; 
     } 
    } 
} 

Link zu meinem Repository: https://github.com/Mortp/CustomMapPinsXamarin

Antwort

1

Dein personalisierter Stift erforderlich ID hier fehlt:

annotationView = mapView.DequeueReusableAnnotation(customPin.Id); 

Notwendigkeit:

var pin = new CustomPin 
      { 
       Id="Xamarin", 
       Pin = new Pin 
       { 
        Type = PinType.Place, 
        Position = new Position(55.240121, 10.469895), 
        Label = "Testing Pins" 
       } 
      }; 

auch statt

if (annotation is MKUserLocation) 
       return null; 

var anno = annotation as MKPointAnnotation; 

Verwendung

var anno = annotation as MKPointAnnotation; 
if (anno == null) 
    return null; 

weil Annotation etwas anderes sein können, wie Sie unten sehen können.

Außerdem habe ich herausgefunden, dass der folgende Code (mit MoveToRegion in diesem Event-Handler) Probleme mit diesem Renderer verursacht, weil GetViewForAnnotation andere Parameter als MKPointAnnotation empfängt, aber Cast-Schutz oben verhindert, dass es abstürzt. Ein weiteres Problem mit dem Code unten, dass, wenn Ihr Pin-Standort weit von Ihrem tatsächlichen Standort entfernt ist, Sie nicht sehen werden, die benutzerdefinierte Pin und Locator Tracker wird immer Ihre Karte in Ihren Standort. Um in solchen Fällen den Pin-Ort zu debuggen, einfach die Zeile "Move" wie folgt auskommentieren.

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

       //map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(position.Latitude, position.Longitude), Distance.FromKilometers(2))); 
      }; 

Die Funktion wird abstürzen OnReverseGeocodeButtonClicked bald :-) weil Ihre Klasse Mitglied Stift nicht zugeordnet ist.

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

Entschuldigung wegen des falschen Codes! Nicht ganz wach, als ich die Frage gepostet habe, ist es jetzt behoben. Vielen Dank für das Feedback. –

+0

Auch mit Ihren Änderungen bekomme ich immer noch eine Null Referenz, wenn der Pin in Sicht kommt. –

+0

Genauer gesagt behauptet es jetzt, dass meine customPin-Liste null ist –