Xamarin表单映射自定义Android渲染器GetMapAsync不调用OnMapReady

时间:2016-08-19 16:20:47

标签: c# android xamarin maps renderer

更新

我遇到了GetMapAsync的问题没有调用OnMapReady我能够通过检查地图是否为空来抑制错误,然后地图将加载非自定义标记。如果我然后稍微移动地图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);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我找到了解决这个问题的方法我移动了代码,我在其自己的函数中设置了地图标记,从那里我在OnElementPropertyChanged中调用该函数和正常执行一样。这会在地图移动时设置标记。要在地图加载时加载自定义标记,我还在onMapReady中调用了设置标记。我的代码现在反映了一个有效的解决方案,我希望我帮助了其他任何可能遇到这个问题的人干杯!