Xamarin.Forms.Maps 2.3.4自定义MapRenderer禁用所有内容

我将Xamarin.Forms和Xamarin.Forms.Maps更新到新版本(2.3.4)后出现问题。

之后我还更新了Android项目中的所有google play服务(以及我讨厌的很多库)。

主要的问题是我有一个自定义MapRenderer用于自定义引脚,在iOS和UWP工作正常,但在Android版本中这个自定义MapRenderer破坏了所有Map。 任何属性更改或方法调用似乎都会被忽略。

例如,我有一个按钮来切换地图类型(混合或街道),该操作永远不会改变它。 我还注意到(根据本教程: https : //developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/map/customized-pin/ )属性“VisibleRegion”永远不会改变所以以下代码从不执行:

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName.Equals("VisibleRegion") && !_isDrawn) { // Do something with your custom map } } 

在里面, if我曾经填充我的自定义引脚(如上面的教程),现在我的地图总是空的。

现在我在IOnMapReadyCallback填充我的地图,它工作正常,但我仍然有绑定问题。

如果我忽略自定义MapRendered(删除assembly线),所有绑定开始正常工作但我的地图现在有旧引脚,所有自定义都消失了(显然)。

在PCL中我有MyMap.MoveToRegion(...)MyMap.MapType = _currentType; 但这些说明仅适用于不使用自定义MapRenderer的情况。

我的自定义MapRenderer与上面的教程几乎相同。

自定义Map是使用C#而不是使用XAML创建的,它没有任何XAML绑定,但如果我正在使用MapRenderer,则完全忽略任何属性更改或方法调用,如MoveToRegion或MapType。

有帮助吗?

谢谢

我已经找到了解决方案。

查看源代码,MapRenderer已经实现了IOnMapReadyCallback ,如果在自定义MapRendered中删除实现,一切都会重新开始工作(但没有自定义)。

MapRenderer将Google地图实例保存在属性NativeMap (也存在属性Map ,即Xamarin表单映射实例),因此我们不再需要实现IOnMapReadyCallback 。 我认为我们需要小心使用NativeMap因为在开始时它可能是null

在我之前提到的方法中,我这样做:

  protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName.Equals("VisibleRegion") && !_isDrawn) { PopulateMap(); OnGoogleMapReady(); } } 

我在OnMapReady中的代码现在进入OnGoogleMapReady()

  private void OnGoogleMapReady() { if (_mapReady) return; NativeMap.InfoWindowClick += OnInfoWindowClick; NativeMap.SetInfoWindowAdapter(this); _mapReady = true; } 

我还在OnElementChanged添加了这个,以删除OnElementChanged中任何已注册的委托

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

目前存在一个将OnMapReady实现为虚拟方法的Pull Request ,因此我们可以在我们的实现中覆盖它,现在确定NativeMap不是null,但为此我们需要等待下一个版本。

你可以在这里阅读更多内容 – > https://forums.xamarin.com/discussion/92565/android-ionmapreadycallback-forms-2-3-4

我得到了同样的问题,由于Xamarin论坛的答案 ,我解决了这个问题 。

这是我的地图渲染器(Android部分)来替换标记的图钉:

 [assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))] namespace MyNamespace.Droid { public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback { GoogleMap map; List customPins; bool isDrawn; protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs e) { base.OnElementChanged(e); if (e.OldElement != null) { map.InfoWindowClick -= OnInfoWindowClick; } if (e.NewElement != null) { var formsMap = (CustomMap)e.NewElement; customPins = formsMap.CustomPins; Control.GetMapAsync(this); } } protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName.Equals ("VisibleRegion") && !isDrawn) { map.Clear (); 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.fake_ic_pin)); map.AddMarker (marker); } isDrawn = true; } } protected override void OnLayout(bool changed, int l, int t, int r, int b) { base.OnLayout(changed, l, t, r, b); if (changed) { isDrawn = false; } } 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 = Android.Net.Uri.Parse(customPin.Url); var intent = new Intent(Intent.ActionView, url); intent.AddFlags(ActivityFlags.NewTask); Android.App.Application.Context.StartActivity(intent); } } void IOnMapReadyCallback.OnMapReady(GoogleMap googleMap) { InvokeOnMapReadyBaseClassHack(googleMap); map = googleMap; map.SetInfoWindowAdapter(this); map.InfoWindowClick += OnInfoWindowClick; } public Android.Views.View GetInfoContents(Marker marker) { return null; } public Android.Views.View GetInfoWindow(Marker marker) { return null; } 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 InvokeOnMapReadyBaseClassHack(GoogleMap googleMap) { System.Reflection.MethodInfo onMapReadyMethodInfo = null; Type baseType = typeof(MapRenderer); foreach (var currentMethod in baseType.GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly)) { if (currentMethod.IsFinal && currentMethod.IsPrivate) { if (string.Equals(currentMethod.Name, "OnMapReady", StringComparison.Ordinal)) { onMapReadyMethodInfo = currentMethod; break; } if (currentMethod.Name.EndsWith(".OnMapReady", StringComparison.Ordinal)) { onMapReadyMethodInfo = currentMethod; break; } } } if (onMapReadyMethodInfo != null) { onMapReadyMethodInfo.Invoke(this, new[] { googleMap }); } } } }