我将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(删除装配线),所有绑定都会正常工作,但我的地图现在有旧引脚,并且所有自定义都已消失(显然)。
在PCL中我有MyMap.MoveToRegion(...)
和MyMap.MapType = _currentType;
之类的内容,但只有在不使用自定义MapRenderer的情况下,这些说明才有效。
我的自定义MapRenderer与上面的教程几乎相同。
使用C#而不是XAML创建自定义Map,它没有任何XAML绑定,但如果我正在使用MapRenderer,则完全忽略任何属性更改或方法调用,如MoveToRegion或MapType。
任何帮助?
由于
答案 0 :(得分:4)
我已经找到了解决方案。
查看源代码,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
中添加了此内容,以删除NativeMap
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
目前存在一个Pull Request实现OnMapReady作为虚方法,所以我们可以在我们的实现中覆盖它,现在确定NativeMap不是null,但为此我们需要等待下一个版本。
你可以在这里阅读更多内容 - > https://forums.xamarin.com/discussion/92565/android-ionmapreadycallback-forms-2-3-4
答案 1 :(得分:0)
我遇到了同样的问题,由于Xamarin论坛上的answer,我解决了这个问题。
这是我的地图渲染器(Android部分),用于替换标记的图像:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MyNamespace.Droid
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback
{
GoogleMap map;
List<CustomPin> customPins;
bool isDrawn;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> 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 });
}
}
}
}