#xamarin #xamarin.forms #xamarin.ios #mkmapviewdelegate
#xamarin #xamarin.forms #xamarin.ios #mkmapviewdelegate
Вопрос:
Когда я пытаюсь запустить свое приложение Xamarin.forms maps, я получаю следующую ошибку: регистрация события перезаписывает существующий делегат. Либо просто используйте events, либо свой собственный делегат: MyApp.iOS.CustomRenderer.MapDelegate MapKit.MKMapView _MKMapViewDelegate Я прикрепил свой файл CustomMapRender к этому вопросу
… C#
using ICCHMapClusterControllerDelegate = MapClustering.ICCHMapClusterControllerDelegate;
using ICCHMapClusterer = MapClustering.ICCHMapClusterer;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MyApp.iOS.CustomRenderer
{
public class CustomMapRenderer : MapRenderer, ICCHMapClusterControllerDelegate//IMKMapViewDelegate
{
MKMapView mapView;
CustomMap customMap;
CCHMapClusterController mapClusterController;
ICCHMapClusterer mapClusterer;
List<MKPointAnnotation> annotations;
CLLocationManager LocationManager;
protected override void Dispose(bool disposing)
{
mapView.ShowsUserLocation = false;
base.Dispose(disposing);
}
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
mapView = Control as MKMapView;
customMap = e.NewElement as CustomMap;
customMap.LocationsLoaded = customMap_LocationsLoaded;
customMap.CenterToMyLocationButtonClicked = CenterToMyLocation;
customMap.OpenCallout = OpenCallout;
LocationManager = new CLLocationManager();
LocationManager.AuthorizationChanged = (object locationmanager, CLAuthorizationChangedEventArgs eventargs) =>
{
if (eventargs.Status == CLAuthorizationStatus.AuthorizedWhenInUse)
{
mapView.ShowsUserLocation = true;
}
else
{
mapView.ShowsUserLocation = false;
}
};
if (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways
|| CLLocationManager.Status == CLAuthorizationStatus.Authorized)
{
mapView.ShowsUserLocation = true;
}
WMSTileOverlay WMSOverlay = new WMSTileOverlay(NetworkConstants.WmsOvermaasLayerUrl, "3")
{
CanReplaceMapContent = false
};
WMSProvincieTileOverlay ProvinceOverLay = new WMSProvincieTileOverlay
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay2 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "2")
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay3 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "3")
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay4 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "4")
{
CanReplaceMapContent = false
};
mapView.AddOverlay(WMSOverlay, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(ProvinceOverLay, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay2, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay3, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay4, MKOverlayLevel.AboveLabels);
Debug.WriteLine("TESTING");
mapClusterController = new CCHMapClusterController(mapView);
mapClusterController.Delegate = new CCHMapClusterControllerDelegate();
mapClusterController.WeakDelegate = this;
// /new CCHMapDelegate();//new CCHMapDelegate();
//new CCHMapClusterControllerDelegate(); //new CCHMapDelegate ();
}
}
private void customMap_LocationsLoaded(object sender, List<Location> locations)
{
RemoveAnnotations();
if (locations == null || locations.Count == 0)
{
return;
}
annotations = new List<MKPointAnnotation>();
foreach (Location location in locations)
{
MKPointAnnotation anno = new MKPointAnnotation();
CLLocationCoordinate2D coord = new CLLocationCoordinate2D(location.Latitude, location.Longitude);
anno.Coordinate = coord;
anno.Title = location.WaterName;
anno.Subtitle = location.City " " location.ExternalReference;
annotations.Add(anno);
}
mapClusterController.AddAnnotations(annotations.ToArray(), null);
mapView.Delegate = new MapDelegate(locations, customMap);
mapClusterController.ReuseExistingClusterAnnotations = false;
}
private void RemoveAnnotations()
{
if (annotations != null amp;amp; annotations.Count != 0)
{
mapClusterController.RemoveAnnotations(annotations.ToArray(), () =>
{
});
}
}
private void CenterToMyLocation(object sender, string e)
{
if (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways
|| CLLocationManager.Status == CLAuthorizationStatus.Authorized)
{
MKCoordinateRegion mapRegion;
mapRegion.Center.Latitude = mapView.UserLocation.Coordinate.Latitude;
mapRegion.Center.Longitude = mapView.UserLocation.Coordinate.Longitude;
mapRegion.Span.LatitudeDelta = 0.2;
mapRegion.Span.LongitudeDelta = 0.2;
mapView.SetRegion(mapRegion, true);
}
if (CLLocationManager.Status == CLAuthorizationStatus.Denied)
{
//check if ios 7/8 this is ios 8
UIAlertController alertController = UIAlertController.Create(title: "Locatie", message: "Om uw locatie te kunnen gebruiken in de app hebben we uw toestemming nodig. "
"dit kunt u in het instellingen menu geven.", preferredStyle: UIAlertControllerStyle.Alert);
alertController.AddAction(UIAlertAction.Create(title: "Annuleren", style: UIAlertActionStyle.Cancel, handler: null));
alertController.AddAction(UIAlertAction.Create(title: "Instellingen", style: UIAlertActionStyle.Default, handler =>
{
NSUrl settingsurl = new NSUrl(UIApplication.OpenSettingsUrlString);
mapView.ShowsUserLocation = true;
UIApplication.SharedApplication.OpenUrl(settingsurl);
}));
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alertController, true, null);
//Old Obsolete
//UIAlertView alert = new UIAlertView("Locatie", "Om uw locatie te kunnen gebruiken in de app hebben we uw toestemming nodig. "
// "dit kunt u in het instellingen menu geven.", null, "Annuleren", "Instellingen");
//alert.Clicked = (object alertsender, UIButtonEventArgs eventargs) => {
// if (eventargs.ButtonIndex != 0)
// {
// NSUrl settingsurl = new NSUrl(UIApplication.OpenSettingsUrlString);
// mapView.ShowsUserLocation = true;
// UIApplication.SharedApplication.OpenUrl(settingsurl);
// }
//};
//alert.Show();
}
if (CLLocationManager.Status == CLAuthorizationStatus.NotDetermined)
{
LocationManager.RequestWhenInUseAuthorization();
}
}
private void OpenCallout(object sender, Location e)
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
Thread.Sleep(1000); // delay execution for 1 s
Device.BeginInvokeOnMainThread(() =>
{
var anno = this.annotations.Where(a => a.Coordinate.Latitude == e.Latitude amp;amp; a.Coordinate.Longitude == e.Longitude).FirstOrDefault();
if (anno != null)
{
this.mapClusterController.SelectAnnotation(anno, e.Latitude, e.Longitude);
}
});
});
}
[Export("mapClusterController:titleForMapClusterAnnotation:")]
public string TitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
var annotationsCount = mapClusterAnnotation.Annotations.Count;
if (annotationsCount != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Title;
}
[Export("mapClusterController:subtitleForMapClusterAnnotation:")]
public string SubtitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
if (mapClusterAnnotation.Annotations.Count != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Subtitle;
}
[Export("mapClusterController:willReuseMapClusterAnnotation:")]
public void WillReuseMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
}
}
internal class MapDelegate : MKMapViewDelegate
{
public MapDelegate(List<Location> locations, CustomMap CustomMap)
: base()
{
Locations = locations;
customMap = CustomMap;
conv = new LevelStatusToColorValueConverter();
defaultColor = Color.FromHex(ColorConstants.WaterLevelBadgeGreen).ToUIColor();
}
static NSObject Invoker = new NSObject();
List<Location> Locations;
string clusterPinId = "cluster";
string nonClusterPinId = "nonCluster";
CustomMap customMap;
LevelStatusToColorValueConverter conv;
UIColor defaultColor;
public override void RegionChanged(MKMapView mapView, bool animated)
{
if (mapView.UserLocationVisible)
{
customMap.ChangeStatusOfLocationImageOnMap(true);
}
else
{
customMap.ChangeStatusOfLocationImageOnMap(false);
}
}
public override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation anno)
{
var annotation = ObjCRuntime.Runtime.GetNSObject(anno.Handle) as CCHMapClusterAnnotation; // this is required to get the underlying annotation object
string useId = nonClusterPinId;
if (anno is MKUserLocation)
return null;
if (annotation == null)
{
return null;
}
string imageName = "";
string imageURL = string.Empty;
string value = string.Empty;
UIColor color = defaultColor;
if (annotation.IsCluster)
{
useId = clusterPinId;
if (Locations != null)
{
List<Location> locations = new List<Location>();
foreach (MKPointAnnotation clusterAnno in annotation.Annotations)
{
string title = clusterAnno.Subtitle;
var location = Locations.Where(l => (l.City " " l.ExternalReference) == title).ToList();
if (location != null amp;amp; location.Count != 0)
{
locations.Add(location.First());
}
}
if (locations.Any())
{
imageName = MapUtil.GetCorrectImageNameForLocations(locations);
}
}
}
else
{
if (Locations != null)
{
string title = annotation.Subtitle;
var location = Locations.Where(l => (l.City " " l.ExternalReference) == title).ToList();
if (location != null amp;amp; location.Count != 0)
{
var currentLocation = location.First();
value = currentLocation.CurrentValueAsString;
var xColor = (Color)conv.Convert(currentLocation.WaterlevelStatus, null, null, null);
color = xColor.ToUIColor();
imageName = MapUtil.GetCorrectImageNameForLocation(currentLocation);
if (currentLocation.HasImage)
{
imageURL = currentLocation.SmallImageURL();
}
else
{
imageURL = NetworkConstants.NoImageSmall;
}
}
}
}
MKAnnotationView pinView = (MKAnnotationView)mapView.DequeueReusableAnnotation(useId);
if (pinView == null)
pinView = new MKAnnotationView(annotation, useId);
if (!annotation.IsCluster)
{
pinView.CanShowCallout = true;
double testWidth = value.Length < 11 ? 65 : 90;
var button = new UIButton(new CGRect(testWidth, 5, 10, 20));
button.SetImage(UIImage.FromBundle("disclosure"), UIControlState.Normal);
JSBadgeView badge = new JSBadgeView(button, JSBadgeView.Alignment.CenterLeft)
{
BadgeBackgroundColor = color,
BadgeStrokeColor = UIColor.Red,
BadgeTextColor = Color.FromHex(ColorConstants.DarkGreyDetailText).ToUIColor(),
BadgeTextFont = UIFont.FromName("AvenirNext-Regular", 11),
BadgeAlignment = JSBadgeView.Alignment.CenterLeft,
BadgeText = value
};
UIView view = new UIView(new CGRect(0, 0, testWidth 10, 30));
view.ClipsToBounds = false;
view.AddSubview(button);
pinView.RightCalloutAccessoryView = view;
if (string.IsNullOrEmpty(imageURL))
{
var imageView = new UIImageView(new CGRect(0, 0, 42, 42));
imageView.Image = UIImage.FromBundle("notavailable");
imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
pinView.LeftCalloutAccessoryView = imageView;
}
else
{
FromUrl(imageURL, pinView);
}
}
pinView.Image = UIImage.FromBundle((string.IsNullOrEmpty(imageName)) ? "flowgreenpin" : imageName);
if (annotation.IsCluster)
{
pinView.CanShowCallout = false;
JSBadgeView badge = new JSBadgeView(pinView, JSBadgeView.Alignment.TopCenter)
{
BadgeBackgroundColor = UIColor.FromRGB(0.451f, 0.847f, 0.988f),
BadgeStrokeColor = UIColor.Red,
BadgeTextColor = UIColor.White,
BadgeTextFont = UIFont.FromName("AvenirNext-Regular", 11),
BadgeAlignment = JSBadgeView.Alignment.TopCenter,
BadgeText = annotation.Annotations.Count.ToString()
};
}
return pinView;
}
public static void InvokedOnMainThread(Action Action)
{
if (NSThread.Current.IsMainThread)
Action();
else
Invoker.BeginInvokeOnMainThread(() => Action());
}
static async Task FromUrl(string uri, MKAnnotationView pinView)
{
using (var httpClient = new HttpClient())
{
Task<byte[]> contentsTask = httpClient.GetByteArrayAsync(uri);
// await! control returns to the caller and the task continues to run on another thread
var contents = await contentsTask;
// load from bytes
var image = UIImage.LoadFromData(NSData.FromArray(contents));
var imageView = new UIImageView(new CGRect(0, 0, 42, 42));
imageView.Image = image;
imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
InvokedOnMainThread(delegate
{
pinView.LeftCalloutAccessoryView = imageView;
});
}
}
public override void DidSelectAnnotationView(MKMapView mapView, MKAnnotationView view)
{
var annotation = ObjCRuntime.Runtime.GetNSObject(view.Annotation.Handle) as CCHMapClusterAnnotation;
if (annotation != null)
{
if (!annotation.IsCluster)
{
UITapGestureRecognizer tap = new UITapGestureRecognizer(OnTap);
view.AddGestureRecognizer(tap);
return;
}
MKMapRect mapRect = annotation.MapRect;
UIEdgeInsets edgeInsets = new UIEdgeInsets(20, 20, 20, 20);
mapView.SetVisibleMapRect(mapRect, edgeInsets, true);
}
mapView.DeselectAnnotation(view.Annotation, true);
}
public override void DidDeselectAnnotationView(MKMapView mapView, MKAnnotationView view)
{
view.GestureRecognizers = null;
}
public override void CalloutAccessoryControlTapped(MKMapView mapView, MKAnnotationView view, UIControl control)
{
if (view != null)
{
var clusterPin = ObjCRuntime.Runtime.GetNSObject(view.Annotation.Handle) as CCHMapClusterAnnotation;
var location = Locations.Where(l => (l.City " " l.ExternalReference) == clusterPin.Subtitle).ToList();
if (location != null amp;amp; location.Count != 0)
{
customMap.ClickedCallout(location.First());
}
}
}
private void OnTap(UIGestureRecognizer gesture)
{
var pinView = gesture.View as MKAnnotationView;
if (pinView != null)
{
var clusterPin = ObjCRuntime.Runtime.GetNSObject(pinView.Annotation.Handle) as CCHMapClusterAnnotation;
var location = Locations.Where(l => (l.City " " l.ExternalReference) == clusterPin.Subtitle).ToList();
if (location != null amp;amp; location.Count != 0)
{
customMap.ClickedCallout(location.First());
}
}
}
public override MKOverlayRenderer OverlayRenderer(MKMapView mapView, IMKOverlay overlay)
{
var osmOverlay = overlay as WMSTileOverlay;
if (osmOverlay != null)
{
return new MKTileOverlayRenderer(new WMSTileOverlay(osmOverlay.BaseUrl, osmOverlay.Layer) { CanReplaceMapContent = false });
}
return new MKTileOverlayRenderer(new WMSProvincieTileOverlay() { CanReplaceMapContent = false });
}
}
internal class CCHMapDelegate : UIViewController, ICCHMapClusterControllerDelegate//CCHMapClusterControllerDelegate
{
[Export("mapClusterController:titleForMapClusterAnnotation:")]
public string TitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
var annotationsCount = mapClusterAnnotation.Annotations.Count;
if (annotationsCount != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Title;
}
//public override string MapClusterTitleForAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
// if (mapClusterAnnotation.Annotations.Count == 1) {
// MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First ();
// return annot.Title;
// }
// return "";
//}
[Export("mapClusterController:subtitleForMapClusterAnnotation:")]
public string SubtitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
if (mapClusterAnnotation.Annotations.Count != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Subtitle;
}
//public override string MapClusterSubtitleForAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
// if (mapClusterAnnotation.Annotations.Count == 1) {
// MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First ();
// return annot.Subtitle;
// }
// return "";
//}
[Export("mapClusterController:willReuseMapClusterAnnotation:")]
public void WillReuseMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
}
//public override void MapClusterWillReuseAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
//}
}
}
…
Комментарии:
1. Вы не можете смешивать обработчики событий C # map и использовать свои собственные
MapDelegate : MKMapViewDelegate
поскольку Xamarin уже использует свой собственный делегат для предоставления обработчиков событий в стиле C #2. Здравствуйте, не могли бы вы указать мне на более конкретное решение. Кажется, я не могу это исправить