Xamarin Forms Maps自定义Android渲染器GetMapAsync未调用OnMapReady
本文关键字:GetMapAsync 调用 OnMapReady Forms Maps 自定义 Android Xamarin | 更新日期: 2023-09-27 18:03:13
更新
我遇到了GetMapAsync不调用OnMapReady的问题。我可以通过检查映射是否为null来抑制错误,然后用非自定义标记加载映射。如果我稍微移动地图,就会加载OnMapReady,然后显示自定义标记。下面是我的自定义渲染器类,如果其他人遇到过这个问题,我将非常感谢您的解决方案。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Views;
using Android.Widget;
using BSi.Mobile.Events.Controls;
using BSi.Mobile.Events.Droid.Renderers;
using BSi.Mobile.Events.Events;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
using View = Xamarin.Forms.View;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace BSi.Mobile.Events.Droid.Renderers
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback
{
GoogleMap map;
IList<CustomPin> customPins;
private CustomPin selectedPin;
bool isDrawn;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
map.InfoWindowClick -= OnInfoWindowClick;
map.MarkerClick -= OnMarkerClick;
map.MapClick -= OnMapClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
selectedPin = formsMap.SelectedPin;
((MapView)Control).GetMapAsync(this);
}
}
public void OnMapReady(GoogleMap googleMap)
{
map = googleMap;
map.InfoWindowClick += OnInfoWindowClick;
map.MarkerClick += OnMarkerClick;
map.MapClick += OnMapClick;
map.SetInfoWindowAdapter(this);
SetMapMarkers();
}
private void SetMapMarkers()
{
map.Clear();
foreach (var pin in customPins)
{
addMarker(pin, false);
}
isDrawn = true;
if (selectedPin != null)
{
addMarker(selectedPin, true);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals("VisibleRegion") && !isDrawn && map != null)
{
SetMapMarkers();
}
else if (e.PropertyName.EndsWith("SelectedPin") && map != null)
{
var customMap = sender as CustomMap;
selectedPin = customMap?.SelectedPin;
if (selectedPin != null)
{
addMarker(selectedPin, true);
}
}
}
private void addMarker(CustomPin pin, bool isSelected)
{
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);
switch (pin.Id)
{
case "Convention":
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.star));
break;
case "cafe":
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.cafe));
break;
case "bar":
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.bar));
break;
default:
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.restaurant));
break;
}
var selectedMarker = map.AddMarker(marker);
if (isSelected)
selectedMarker.ShowInfoWindow();
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
//Catches Exception incase user needs to update google play services
try
{
base.OnLayout(changed, l, t, r, b);
if (changed)
{
isDrawn = false;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
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);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
switch (customPin.Id)
{
case "Conference":
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
break;
default:
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
break;
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
var infoPhone = view.FindViewById<TextView>(Resource.Id.InfoWindowPhone);
var infoWebsite = view.FindViewById<TextView>(Resource.Id.InfoWindowWebsite);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
else
{
infoTitle.Visibility = ViewStates.Gone;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
else
{
infoSubtitle.Visibility = ViewStates.Gone;
}
if (infoPhone != null && customPin.Phone != null)
{
infoPhone.Text = customPin.Phone;
}
else
{
infoPhone.Visibility = ViewStates.Gone;
}
if (infoWebsite != null && customPin.Url != null)
{
infoWebsite.Text = customPin.Url;
}
else
{
infoWebsite.Visibility = ViewStates.Gone;
}
return view;
}
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;
}
private void OnMarkerClick(object sender, GoogleMap.MarkerClickEventArgs e)
{
e.Handled = false;
App.EventAggregator?.GetEvent<MapClickedEvent>().Publish(new Pin { Position = new Position(e.Marker.Position.Latitude, e.Marker.Position.Longitude), Label = e.Marker.Title});
}
private void OnMapClick(object sender, GoogleMap.MapClickEventArgs e)
{
App.EventAggregator?.GetEvent<MapClickedEvent>().Publish(null);
}
}
}
我找到了一个解决方案来解决这个问题,我移动了代码,在它自己的函数中设置映射标记,从那里我在OnElementPropertyChanged中调用该函数,就像正常执行一样。这将在地图移动时设置标记。为了在加载地图时加载自定义标记,我还调用了onMapReady内部的设置标记。我上面的代码现在反映了一个有效的解决方案,我希望我已经帮助了其他可能遇到这个问题的人干杯!