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

Xamarin Forms Maps自定义Android渲染器GetMapAsync未调用OnMapReady

我找到了一个解决方案来解决这个问题,我移动了代码,在它自己的函数中设置映射标记,从那里我在OnElementPropertyChanged中调用该函数,就像正常执行一样。这将在地图移动时设置标记。为了在加载地图时加载自定义标记,我还调用了onMapReady内部的设置标记。我上面的代码现在反映了一个有效的解决方案,我希望我已经帮助了其他可能遇到这个问题的人干杯!