2016-03-22 23:02:25 +03:00
|
|
|
using System;
|
2016-09-16 21:55:38 +03:00
|
|
|
using System.Collections;
|
2016-03-22 23:02:25 +03:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
using System.Collections.Specialized;
|
|
|
|
using System.ComponentModel;
|
|
|
|
using System.Linq;
|
2019-11-05 17:52:34 +03:00
|
|
|
using Android;
|
2017-10-09 20:51:55 +03:00
|
|
|
using Android.Content;
|
2019-11-05 17:52:34 +03:00
|
|
|
using Android.Content.PM;
|
2016-03-22 23:02:25 +03:00
|
|
|
using Android.Gms.Maps;
|
|
|
|
using Android.Gms.Maps.Model;
|
|
|
|
using Android.OS;
|
2020-01-10 23:35:41 +03:00
|
|
|
#if __ANDROID_29__
|
|
|
|
using AndroidX.Core.Content;
|
|
|
|
#else
|
2019-11-05 17:52:34 +03:00
|
|
|
using Android.Support.V4.Content;
|
2020-01-10 23:35:41 +03:00
|
|
|
#endif
|
2016-03-22 23:02:25 +03:00
|
|
|
using Java.Lang;
|
2017-03-07 22:56:24 +03:00
|
|
|
using Xamarin.Forms.Internals;
|
2016-03-22 23:02:25 +03:00
|
|
|
using Xamarin.Forms.Platform.Android;
|
|
|
|
using Math = System.Math;
|
2019-08-29 19:47:57 +03:00
|
|
|
using APolyline = Android.Gms.Maps.Model.Polyline;
|
|
|
|
using APolygon = Android.Gms.Maps.Model.Polygon;
|
2020-01-30 00:38:34 +03:00
|
|
|
using ACircle = Android.Gms.Maps.Model.Circle;
|
2016-03-22 23:02:25 +03:00
|
|
|
|
|
|
|
namespace Xamarin.Forms.Maps.Android
|
|
|
|
{
|
2018-05-15 18:16:52 +03:00
|
|
|
public class MapRenderer : ViewRenderer<Map, MapView>, GoogleMap.IOnCameraMoveListener, IOnMapReadyCallback
|
2016-03-22 23:02:25 +03:00
|
|
|
{
|
2016-09-16 21:55:38 +03:00
|
|
|
const string MoveMessageName = "MapMoveToRegion";
|
2016-03-22 23:02:25 +03:00
|
|
|
|
|
|
|
static Bundle s_bundle;
|
2016-09-16 21:55:38 +03:00
|
|
|
|
|
|
|
bool _disposed;
|
|
|
|
|
|
|
|
bool _init = true;
|
2016-03-22 23:02:25 +03:00
|
|
|
|
|
|
|
List<Marker> _markers;
|
2019-08-29 19:47:57 +03:00
|
|
|
List<APolyline> _polylines;
|
|
|
|
List<APolygon> _polygons;
|
2020-01-30 00:38:34 +03:00
|
|
|
List<ACircle> _circles;
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2017-10-09 20:51:55 +03:00
|
|
|
public MapRenderer(Context context) : base(context)
|
|
|
|
{
|
|
|
|
AutoPackage = false;
|
|
|
|
}
|
|
|
|
|
2017-10-20 23:02:16 +03:00
|
|
|
[Obsolete("This constructor is obsolete as of version 2.5. Please use MapRenderer(Context) instead.")]
|
2019-01-10 14:53:48 +03:00
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
2016-09-16 21:55:38 +03:00
|
|
|
public MapRenderer()
|
|
|
|
{
|
|
|
|
AutoPackage = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected Map Map => Element;
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2017-03-21 13:38:36 +03:00
|
|
|
protected GoogleMap NativeMap;
|
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
internal static Bundle Bundle
|
|
|
|
{
|
|
|
|
set { s_bundle = value; }
|
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
public override SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint)
|
2016-03-22 23:02:25 +03:00
|
|
|
{
|
2016-09-16 21:55:38 +03:00
|
|
|
return new SizeRequest(new Size(Context.ToPixels(40), Context.ToPixels(40)));
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
|
|
|
|
2016-08-30 20:37:07 +03:00
|
|
|
protected override MapView CreateNativeControl()
|
|
|
|
{
|
|
|
|
return new MapView(Context);
|
|
|
|
}
|
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
protected override void Dispose(bool disposing)
|
2016-03-22 23:02:25 +03:00
|
|
|
{
|
2016-09-27 13:51:22 +03:00
|
|
|
if (_disposed)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
2016-09-27 13:51:22 +03:00
|
|
|
return;
|
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2016-09-27 13:51:22 +03:00
|
|
|
_disposed = true;
|
|
|
|
|
|
|
|
if (disposing)
|
|
|
|
{
|
|
|
|
if (Element != null)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
|
|
|
MessagingCenter.Unsubscribe<Map, MapSpan>(this, MoveMessageName);
|
2018-05-15 14:27:29 +03:00
|
|
|
|
2019-08-29 19:47:57 +03:00
|
|
|
((ObservableCollection<Pin>)Element.Pins).CollectionChanged -= OnPinCollectionChanged;
|
2018-05-15 14:27:29 +03:00
|
|
|
foreach (Pin pin in Element.Pins)
|
|
|
|
{
|
|
|
|
pin.PropertyChanged -= PinOnPropertyChanged;
|
|
|
|
}
|
2019-08-29 19:47:57 +03:00
|
|
|
|
|
|
|
((ObservableCollection<MapElement>)Element.MapElements).CollectionChanged -= OnMapElementCollectionChanged;
|
|
|
|
foreach (MapElement child in Element.MapElements)
|
|
|
|
{
|
|
|
|
child.PropertyChanged -= MapElementPropertyChanged;
|
|
|
|
}
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2016-09-27 13:51:22 +03:00
|
|
|
if (NativeMap != null)
|
2019-04-24 03:57:22 +03:00
|
|
|
{
|
|
|
|
NativeMap.MyLocationEnabled = false;
|
|
|
|
NativeMap.SetOnCameraMoveListener(null);
|
2019-08-14 03:41:11 +03:00
|
|
|
NativeMap.MarkerClick -= OnMarkerClick;
|
|
|
|
NativeMap.InfoWindowClick -= OnInfoWindowClick;
|
2019-04-24 03:57:22 +03:00
|
|
|
NativeMap.MapClick -= OnMapClick;
|
|
|
|
NativeMap.Dispose();
|
2017-03-21 13:38:36 +03:00
|
|
|
NativeMap = null;
|
2019-04-24 03:57:22 +03:00
|
|
|
}
|
2016-09-27 13:51:22 +03:00
|
|
|
|
|
|
|
Control?.OnDestroy();
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
base.Dispose(disposing);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
|
|
|
|
{
|
|
|
|
base.OnElementChanged(e);
|
|
|
|
|
|
|
|
MapView oldMapView = Control;
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
MapView mapView = CreateNativeControl();
|
|
|
|
mapView.OnCreate(s_bundle);
|
|
|
|
mapView.OnResume();
|
|
|
|
SetNativeControl(mapView);
|
|
|
|
|
|
|
|
if (e.OldElement != null)
|
|
|
|
{
|
|
|
|
Map oldMapModel = e.OldElement;
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2019-08-29 19:47:57 +03:00
|
|
|
((ObservableCollection<Pin>)oldMapModel.Pins).CollectionChanged -= OnPinCollectionChanged;
|
2018-05-15 14:27:29 +03:00
|
|
|
foreach (Pin pin in oldMapModel.Pins)
|
|
|
|
{
|
|
|
|
pin.PropertyChanged -= PinOnPropertyChanged;
|
|
|
|
}
|
|
|
|
|
2019-08-29 19:47:57 +03:00
|
|
|
((ObservableCollection<MapElement>)oldMapModel.MapElements).CollectionChanged -= OnMapElementCollectionChanged;
|
|
|
|
foreach (MapElement child in oldMapModel.MapElements)
|
|
|
|
{
|
|
|
|
child.PropertyChanged -= MapElementPropertyChanged;
|
|
|
|
}
|
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
MessagingCenter.Unsubscribe<Map, MapSpan>(this, MoveMessageName);
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2017-03-21 13:38:36 +03:00
|
|
|
if (NativeMap != null)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
2017-10-09 23:25:45 +03:00
|
|
|
NativeMap.SetOnCameraMoveListener(null);
|
2019-08-14 03:41:11 +03:00
|
|
|
NativeMap.MarkerClick -= OnMarkerClick;
|
|
|
|
NativeMap.InfoWindowClick -= OnInfoWindowClick;
|
2019-04-24 03:57:22 +03:00
|
|
|
NativeMap.MapClick -= OnMapClick;
|
2017-03-21 13:38:36 +03:00
|
|
|
NativeMap = null;
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
oldMapView.Dispose();
|
|
|
|
}
|
|
|
|
|
2017-03-21 13:38:36 +03:00
|
|
|
Control.GetMapAsync(this);
|
2016-09-16 21:55:38 +03:00
|
|
|
|
|
|
|
MessagingCenter.Subscribe<Map, MapSpan>(this, MoveMessageName, OnMoveToRegionMessage, Map);
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2019-08-29 19:47:57 +03:00
|
|
|
((INotifyCollectionChanged)Map.Pins).CollectionChanged += OnPinCollectionChanged;
|
|
|
|
((INotifyCollectionChanged)Map.MapElements).CollectionChanged += OnMapElementCollectionChanged;
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
2016-03-22 23:02:25 +03:00
|
|
|
{
|
2016-09-16 21:55:38 +03:00
|
|
|
base.OnElementPropertyChanged(sender, e);
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
if (e.PropertyName == Map.MapTypeProperty.PropertyName)
|
|
|
|
{
|
2016-03-22 23:02:25 +03:00
|
|
|
SetMapType();
|
|
|
|
return;
|
|
|
|
}
|
2016-09-16 21:55:38 +03:00
|
|
|
|
|
|
|
GoogleMap gmap = NativeMap;
|
2016-03-22 23:02:25 +03:00
|
|
|
if (gmap == null)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
2016-03-22 23:02:25 +03:00
|
|
|
return;
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
|
|
|
|
if (e.PropertyName == Map.IsShowingUserProperty.PropertyName)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
2019-11-05 17:52:34 +03:00
|
|
|
SetUserVisible();
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
else if (e.PropertyName == Map.HasScrollEnabledProperty.PropertyName)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
2016-03-22 23:02:25 +03:00
|
|
|
gmap.UiSettings.ScrollGesturesEnabled = Map.HasScrollEnabled;
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
|
|
|
else if (e.PropertyName == Map.HasZoomEnabledProperty.PropertyName)
|
|
|
|
{
|
2016-03-22 23:02:25 +03:00
|
|
|
gmap.UiSettings.ZoomControlsEnabled = Map.HasZoomEnabled;
|
|
|
|
gmap.UiSettings.ZoomGesturesEnabled = Map.HasZoomEnabled;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
protected override void OnLayout(bool changed, int l, int t, int r, int b)
|
2016-03-22 23:02:25 +03:00
|
|
|
{
|
2016-09-16 21:55:38 +03:00
|
|
|
base.OnLayout(changed, l, t, r, b);
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
if (_init)
|
|
|
|
{
|
2017-03-21 13:38:36 +03:00
|
|
|
if (NativeMap != null)
|
|
|
|
{
|
|
|
|
MoveToRegion(Element.LastMoveToRegion, false);
|
2019-08-29 19:47:57 +03:00
|
|
|
OnPinCollectionChanged(Element.Pins, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
|
|
|
OnMapElementCollectionChanged(Element.MapElements, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
2017-03-21 13:38:36 +03:00
|
|
|
_init = false;
|
|
|
|
}
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
|
|
|
else if (changed)
|
|
|
|
{
|
2017-03-21 13:38:36 +03:00
|
|
|
if (NativeMap != null)
|
|
|
|
{
|
|
|
|
UpdateVisibleRegion(NativeMap.CameraPosition.Target);
|
|
|
|
}
|
2019-07-04 03:05:17 +03:00
|
|
|
|
2019-08-29 19:47:57 +03:00
|
|
|
if (Element.MoveToLastRegionOnLayoutChange)
|
2019-07-04 03:05:17 +03:00
|
|
|
MoveToRegion(Element.LastMoveToRegion, false);
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
|
|
|
}
|
2018-05-15 18:16:52 +03:00
|
|
|
|
2017-04-12 01:52:04 +03:00
|
|
|
protected virtual void OnMapReady(GoogleMap map)
|
|
|
|
{
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2018-05-15 18:16:52 +03:00
|
|
|
|
2017-10-09 23:25:45 +03:00
|
|
|
map.SetOnCameraMoveListener(this);
|
2019-08-14 03:41:11 +03:00
|
|
|
map.MarkerClick += OnMarkerClick;
|
|
|
|
map.InfoWindowClick += OnInfoWindowClick;
|
2019-04-24 03:57:22 +03:00
|
|
|
map.MapClick += OnMapClick;
|
2018-05-15 18:16:52 +03:00
|
|
|
|
2017-04-12 01:52:04 +03:00
|
|
|
map.UiSettings.ZoomControlsEnabled = Map.HasZoomEnabled;
|
|
|
|
map.UiSettings.ZoomGesturesEnabled = Map.HasZoomEnabled;
|
|
|
|
map.UiSettings.ScrollGesturesEnabled = Map.HasScrollEnabled;
|
2019-11-05 17:52:34 +03:00
|
|
|
SetUserVisible();
|
2017-04-12 01:52:04 +03:00
|
|
|
SetMapType();
|
|
|
|
}
|
2018-05-15 18:16:52 +03:00
|
|
|
|
2017-04-12 01:52:04 +03:00
|
|
|
protected virtual MarkerOptions CreateMarker(Pin pin)
|
|
|
|
{
|
|
|
|
var opts = new MarkerOptions();
|
|
|
|
opts.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
|
|
|
|
opts.SetTitle(pin.Label);
|
|
|
|
opts.SetSnippet(pin.Address);
|
2018-05-15 18:16:52 +03:00
|
|
|
|
2017-04-12 01:52:04 +03:00
|
|
|
return opts;
|
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
void AddPins(IList pins)
|
2016-03-22 23:02:25 +03:00
|
|
|
{
|
2016-09-16 21:55:38 +03:00
|
|
|
GoogleMap map = NativeMap;
|
2016-03-22 23:02:25 +03:00
|
|
|
if (map == null)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
2016-03-22 23:02:25 +03:00
|
|
|
return;
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
|
|
|
|
if (_markers == null)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
|
|
|
_markers = new List<Marker>();
|
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
_markers.AddRange(pins.Cast<Pin>().Select(p =>
|
|
|
|
{
|
|
|
|
Pin pin = p;
|
2017-04-12 01:52:04 +03:00
|
|
|
var opts = CreateMarker(pin);
|
2016-09-16 21:55:38 +03:00
|
|
|
var marker = map.AddMarker(opts);
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2018-05-15 14:27:29 +03:00
|
|
|
pin.PropertyChanged += PinOnPropertyChanged;
|
|
|
|
|
2016-03-22 23:02:25 +03:00
|
|
|
// associate pin with marker for later lookup in event handlers
|
2019-03-27 21:38:38 +03:00
|
|
|
pin.MarkerId = marker.Id;
|
2016-03-22 23:02:25 +03:00
|
|
|
return marker;
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2018-05-15 14:27:29 +03:00
|
|
|
void PinOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
|
|
{
|
|
|
|
Pin pin = (Pin)sender;
|
2018-09-17 21:16:29 +03:00
|
|
|
Marker marker = GetMarkerForPin(pin);
|
2018-05-15 14:27:29 +03:00
|
|
|
|
|
|
|
if (marker == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e.PropertyName == Pin.LabelProperty.PropertyName)
|
|
|
|
{
|
|
|
|
marker.Title = pin.Label;
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == Pin.AddressProperty.PropertyName)
|
|
|
|
{
|
|
|
|
marker.Snippet = pin.Address;
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == Pin.PositionProperty.PropertyName)
|
|
|
|
{
|
|
|
|
marker.Position = new LatLng(pin.Position.Latitude, pin.Position.Longitude);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-17 21:16:29 +03:00
|
|
|
protected Marker GetMarkerForPin(Pin pin)
|
|
|
|
{
|
2020-01-30 00:38:34 +03:00
|
|
|
Marker targetMarker = null;
|
|
|
|
|
|
|
|
if (_markers != null)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < _markers.Count; i++)
|
|
|
|
{
|
|
|
|
var marker = _markers[i];
|
|
|
|
if (marker.Id == (string)pin.MarkerId)
|
|
|
|
{
|
|
|
|
targetMarker = marker;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return targetMarker;
|
2018-09-17 21:16:29 +03:00
|
|
|
}
|
|
|
|
|
2019-08-14 03:41:11 +03:00
|
|
|
protected Pin GetPinForMarker(Marker marker)
|
2016-03-22 23:02:25 +03:00
|
|
|
{
|
|
|
|
Pin targetPin = null;
|
2019-08-14 03:41:11 +03:00
|
|
|
|
|
|
|
for (int i = 0; i < Map.Pins.Count; i++)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
2019-08-14 03:41:11 +03:00
|
|
|
var pin = Map.Pins[i];
|
|
|
|
if ((string)pin.MarkerId == marker.Id)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
2019-08-14 03:41:11 +03:00
|
|
|
targetPin = pin;
|
|
|
|
break;
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
2019-08-14 03:41:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return targetPin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnMarkerClick(object sender, GoogleMap.MarkerClickEventArgs e)
|
|
|
|
{
|
|
|
|
var pin = GetPinForMarker(e.Marker);
|
|
|
|
|
|
|
|
if (pin == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setting e.Handled = true will prevent the info window from being presented
|
|
|
|
// SendMarkerClick() returns the value of PinClickedEventArgs.HideInfoWindow
|
|
|
|
bool handled = pin.SendMarkerClick();
|
|
|
|
e.Handled = handled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
|
|
|
|
{
|
|
|
|
var marker = e.Marker;
|
|
|
|
var pin = GetPinForMarker(marker);
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2019-08-14 03:41:11 +03:00
|
|
|
if (pin == null)
|
|
|
|
{
|
|
|
|
return;
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
|
|
|
|
2019-08-14 03:41:11 +03:00
|
|
|
#pragma warning disable CS0618
|
|
|
|
pin.SendTap();
|
|
|
|
#pragma warning restore CS0618
|
|
|
|
|
|
|
|
// SendInfoWindowClick() returns the value of PinClickedEventArgs.HideInfoWindow
|
|
|
|
bool hideInfoWindow = pin.SendInfoWindowClick();
|
|
|
|
if (hideInfoWindow)
|
|
|
|
{
|
|
|
|
marker.HideInfoWindow();
|
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
|
|
|
|
2019-04-24 03:57:22 +03:00
|
|
|
void OnMapClick(object sender, GoogleMap.MapClickEventArgs e)
|
|
|
|
{
|
|
|
|
Map.SendMapClicked(new Position(e.Point.Latitude, e.Point.Longitude));
|
|
|
|
}
|
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
void MoveToRegion(MapSpan span, bool animate)
|
2016-03-22 23:02:25 +03:00
|
|
|
{
|
2016-09-16 21:55:38 +03:00
|
|
|
GoogleMap map = NativeMap;
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
span = span.ClampLatitude(85, -85);
|
|
|
|
var ne = new LatLng(span.Center.Latitude + span.LatitudeDegrees / 2,
|
|
|
|
span.Center.Longitude + span.LongitudeDegrees / 2);
|
|
|
|
var sw = new LatLng(span.Center.Latitude - span.LatitudeDegrees / 2,
|
|
|
|
span.Center.Longitude - span.LongitudeDegrees / 2);
|
|
|
|
CameraUpdate update = CameraUpdateFactory.NewLatLngBounds(new LatLngBounds(sw, ne), 0);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (animate)
|
|
|
|
{
|
|
|
|
map.AnimateCamera(update);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
map.MoveCamera(update);
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
|
|
|
catch (IllegalStateException exc)
|
|
|
|
{
|
|
|
|
System.Diagnostics.Debug.WriteLine("MoveToRegion exception: " + exc);
|
2016-09-27 13:51:22 +03:00
|
|
|
Log.Warning("Xamarin.Forms MapRenderer", $"MoveToRegion exception: {exc}");
|
2016-09-16 21:55:38 +03:00
|
|
|
}
|
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
|
2019-08-29 19:47:57 +03:00
|
|
|
void OnPinCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
|
2016-09-16 21:55:38 +03:00
|
|
|
{
|
|
|
|
switch (notifyCollectionChangedEventArgs.Action)
|
|
|
|
{
|
|
|
|
case NotifyCollectionChangedAction.Add:
|
|
|
|
AddPins(notifyCollectionChangedEventArgs.NewItems);
|
|
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
|
|
RemovePins(notifyCollectionChangedEventArgs.OldItems);
|
|
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Replace:
|
|
|
|
RemovePins(notifyCollectionChangedEventArgs.OldItems);
|
|
|
|
AddPins(notifyCollectionChangedEventArgs.NewItems);
|
|
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Reset:
|
2020-01-30 00:38:34 +03:00
|
|
|
if (_markers != null)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < _markers.Count; i++)
|
|
|
|
_markers[i].Remove();
|
|
|
|
|
|
|
|
_markers = null;
|
|
|
|
}
|
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
AddPins((IList)Element.Pins);
|
|
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Move:
|
|
|
|
//do nothing
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnMoveToRegionMessage(Map s, MapSpan a)
|
|
|
|
{
|
|
|
|
MoveToRegion(a, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemovePins(IList pins)
|
|
|
|
{
|
|
|
|
GoogleMap map = NativeMap;
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (_markers == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (Pin p in pins)
|
|
|
|
{
|
2018-05-15 14:27:29 +03:00
|
|
|
p.PropertyChanged -= PinOnPropertyChanged;
|
2018-09-17 21:16:29 +03:00
|
|
|
var marker = GetMarkerForPin(p);
|
2018-05-15 14:27:29 +03:00
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
if (marker == null)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
marker.Remove();
|
|
|
|
_markers.Remove(marker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetMapType()
|
|
|
|
{
|
|
|
|
GoogleMap map = NativeMap;
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
|
|
|
|
2016-09-16 21:55:38 +03:00
|
|
|
switch (Map.MapType)
|
|
|
|
{
|
|
|
|
case MapType.Street:
|
|
|
|
map.MapType = GoogleMap.MapTypeNormal;
|
|
|
|
break;
|
|
|
|
case MapType.Satellite:
|
|
|
|
map.MapType = GoogleMap.MapTypeSatellite;
|
|
|
|
break;
|
|
|
|
case MapType.Hybrid:
|
|
|
|
map.MapType = GoogleMap.MapTypeHybrid;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateVisibleRegion(LatLng pos)
|
|
|
|
{
|
|
|
|
GoogleMap map = NativeMap;
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Projection projection = map.Projection;
|
|
|
|
int width = Control.Width;
|
|
|
|
int height = Control.Height;
|
|
|
|
LatLng ul = projection.FromScreenLocation(new global::Android.Graphics.Point(0, 0));
|
|
|
|
LatLng ur = projection.FromScreenLocation(new global::Android.Graphics.Point(width, 0));
|
|
|
|
LatLng ll = projection.FromScreenLocation(new global::Android.Graphics.Point(0, height));
|
|
|
|
LatLng lr = projection.FromScreenLocation(new global::Android.Graphics.Point(width, height));
|
|
|
|
double dlat = Math.Max(Math.Abs(ul.Latitude - lr.Latitude), Math.Abs(ur.Latitude - ll.Latitude));
|
|
|
|
double dlong = Math.Max(Math.Abs(ul.Longitude - lr.Longitude), Math.Abs(ur.Longitude - ll.Longitude));
|
2017-07-24 23:23:14 +03:00
|
|
|
Element.SetVisibleRegion(new MapSpan(new Position(pos.Latitude, pos.Longitude), dlat, dlong));
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
2017-03-21 13:38:36 +03:00
|
|
|
|
2019-08-29 19:47:57 +03:00
|
|
|
void MapElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
|
|
{
|
|
|
|
switch (sender)
|
|
|
|
{
|
|
|
|
case Polyline polyline:
|
|
|
|
{
|
|
|
|
PolylineOnPropertyChanged(polyline, e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Polygon polygon:
|
|
|
|
{
|
|
|
|
PolygonOnPropertyChanged(polygon, e);
|
|
|
|
break;
|
|
|
|
}
|
2020-01-30 00:38:34 +03:00
|
|
|
case Circle circle:
|
|
|
|
{
|
|
|
|
CircleOnPropertyChanged(circle, e);
|
|
|
|
break;
|
|
|
|
}
|
2019-08-29 19:47:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnMapElementCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
|
|
{
|
|
|
|
switch (e.Action)
|
|
|
|
{
|
|
|
|
case NotifyCollectionChangedAction.Add:
|
|
|
|
AddMapElements(e.NewItems.Cast<MapElement>());
|
|
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
|
|
RemoveMapElements(e.OldItems.Cast<MapElement>());
|
|
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Replace:
|
|
|
|
RemoveMapElements(e.OldItems.Cast<MapElement>());
|
|
|
|
AddMapElements(e.NewItems.Cast<MapElement>());
|
|
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Reset:
|
|
|
|
if (_polylines != null)
|
|
|
|
{
|
2020-01-30 00:38:34 +03:00
|
|
|
for(int i = 0; i < _polylines.Count; i++)
|
|
|
|
_polylines[i].Remove();
|
|
|
|
|
|
|
|
_polylines = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_polygons != null)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < _polygons.Count; i++)
|
|
|
|
_polygons[i].Remove();
|
|
|
|
|
|
|
|
_polygons = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_circles != null)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < _circles.Count; i++)
|
|
|
|
_circles[i].Remove();
|
|
|
|
|
|
|
|
_circles = null;
|
2019-08-29 19:47:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
AddMapElements(Element.MapElements);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddMapElements(IEnumerable<MapElement> mapElements)
|
|
|
|
{
|
|
|
|
foreach (var element in mapElements)
|
|
|
|
{
|
|
|
|
element.PropertyChanged += MapElementPropertyChanged;
|
|
|
|
|
|
|
|
switch (element)
|
|
|
|
{
|
|
|
|
case Polyline polyline:
|
|
|
|
AddPolyline(polyline);
|
|
|
|
break;
|
|
|
|
case Polygon polygon:
|
|
|
|
AddPolygon(polygon);
|
|
|
|
break;
|
2020-01-30 00:38:34 +03:00
|
|
|
case Circle circle:
|
|
|
|
AddCircle(circle);
|
|
|
|
break;
|
2019-08-29 19:47:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveMapElements(IEnumerable<MapElement> mapElements)
|
|
|
|
{
|
|
|
|
foreach (var element in mapElements)
|
|
|
|
{
|
|
|
|
element.PropertyChanged -= MapElementPropertyChanged;
|
|
|
|
|
|
|
|
switch (element)
|
|
|
|
{
|
|
|
|
case Polyline polyline:
|
|
|
|
RemovePolyline(polyline);
|
|
|
|
break;
|
|
|
|
case Polygon polygon:
|
|
|
|
RemovePolygon(polygon);
|
|
|
|
break;
|
2020-01-30 00:38:34 +03:00
|
|
|
case Circle circle:
|
|
|
|
RemoveCircle(circle);
|
|
|
|
break;
|
2019-08-29 19:47:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#region Polylines
|
|
|
|
|
|
|
|
protected virtual PolylineOptions CreatePolylineOptions(Polyline polyline)
|
|
|
|
{
|
|
|
|
var opts = new PolylineOptions();
|
|
|
|
|
|
|
|
opts.InvokeColor(polyline.StrokeColor.ToAndroid(Color.Black));
|
|
|
|
opts.InvokeWidth(polyline.StrokeWidth);
|
|
|
|
|
|
|
|
foreach (var position in polyline.Geopath)
|
|
|
|
{
|
|
|
|
opts.Points.Add(new LatLng(position.Latitude, position.Longitude));
|
|
|
|
}
|
|
|
|
|
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected APolyline GetNativePolyline(Polyline polyline)
|
|
|
|
{
|
2020-01-30 00:38:34 +03:00
|
|
|
APolyline targetPolyline = null;
|
|
|
|
|
|
|
|
if (_polylines != null)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < _polylines.Count; i++)
|
|
|
|
{
|
|
|
|
var native = _polylines[i];
|
|
|
|
if (native.Id == (string)polyline.MapElementId)
|
|
|
|
{
|
|
|
|
targetPolyline = native;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return targetPolyline;
|
2019-08-29 19:47:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
protected Polyline GetFormsPolyline(APolyline polyline)
|
|
|
|
{
|
|
|
|
Polyline targetPolyline = null;
|
|
|
|
|
|
|
|
for (int i = 0; i < Map.MapElements.Count; i++)
|
|
|
|
{
|
|
|
|
var element = Map.MapElements[i];
|
|
|
|
if ((string)element.MapElementId == polyline.Id)
|
|
|
|
{
|
|
|
|
targetPolyline = element as Polyline;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return targetPolyline;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolylineOnPropertyChanged(Polyline formsPolyline, PropertyChangedEventArgs e)
|
|
|
|
{
|
|
|
|
var nativePolyline = GetNativePolyline(formsPolyline);
|
|
|
|
|
|
|
|
if (nativePolyline == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e.PropertyName == MapElement.StrokeColorProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativePolyline.Color = formsPolyline.StrokeColor.ToAndroid(Color.Black);
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == MapElement.StrokeWidthProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativePolyline.Width = formsPolyline.StrokeWidth;
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == nameof(Polyline.Geopath))
|
|
|
|
{
|
|
|
|
nativePolyline.Points = formsPolyline.Geopath.Select(position => new LatLng(position.Latitude, position.Longitude)).ToList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddPolyline(Polyline polyline)
|
|
|
|
{
|
|
|
|
var map = NativeMap;
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_polylines == null)
|
|
|
|
{
|
|
|
|
_polylines = new List<APolyline>();
|
|
|
|
}
|
|
|
|
|
|
|
|
var options = CreatePolylineOptions(polyline);
|
|
|
|
var nativePolyline = map.AddPolyline(options);
|
|
|
|
|
|
|
|
polyline.MapElementId = nativePolyline.Id;
|
|
|
|
|
|
|
|
_polylines.Add(nativePolyline);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemovePolyline(Polyline polyline)
|
|
|
|
{
|
|
|
|
var native = GetNativePolyline(polyline);
|
|
|
|
|
|
|
|
if (native != null)
|
|
|
|
{
|
|
|
|
native.Remove();
|
|
|
|
_polylines.Remove(native);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region Polygons
|
|
|
|
|
|
|
|
protected virtual PolygonOptions CreatePolygonOptions(Polygon polygon)
|
|
|
|
{
|
|
|
|
var opts = new PolygonOptions();
|
|
|
|
|
|
|
|
opts.InvokeStrokeColor(polygon.StrokeColor.ToAndroid(Color.Black));
|
|
|
|
opts.InvokeStrokeWidth(polygon.StrokeWidth);
|
|
|
|
|
|
|
|
if (!polygon.StrokeColor.IsDefault)
|
|
|
|
opts.InvokeFillColor(polygon.FillColor.ToAndroid());
|
|
|
|
|
|
|
|
// Will throw an exception when added to the map if Points is empty
|
|
|
|
if (polygon.Geopath.Count == 0)
|
|
|
|
{
|
|
|
|
opts.Points.Add(new LatLng(0, 0));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
foreach (var position in polygon.Geopath)
|
|
|
|
{
|
|
|
|
opts.Points.Add(new LatLng(position.Latitude, position.Longitude));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected APolygon GetNativePolygon(Polygon polygon)
|
|
|
|
{
|
2020-01-30 00:38:34 +03:00
|
|
|
APolygon targetPolygon = null;
|
|
|
|
|
|
|
|
if (_polygons != null)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < _polygons.Count; i++)
|
|
|
|
{
|
|
|
|
var native = _polygons[i];
|
|
|
|
if (native.Id == (string)polygon.MapElementId)
|
|
|
|
{
|
|
|
|
targetPolygon = native;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return targetPolygon;
|
2019-08-29 19:47:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
protected Polygon GetFormsPolygon(APolygon polygon)
|
|
|
|
{
|
|
|
|
Polygon targetPolygon = null;
|
|
|
|
|
|
|
|
for (int i = 0; i < Element.MapElements.Count; i++)
|
|
|
|
{
|
|
|
|
var element = Element.MapElements[i];
|
|
|
|
if ((string)element.MapElementId == polygon.Id)
|
|
|
|
{
|
|
|
|
targetPolygon = (Polygon)element;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return targetPolygon;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolygonOnPropertyChanged(Polygon polygon, PropertyChangedEventArgs e)
|
|
|
|
{
|
|
|
|
var nativePolygon = GetNativePolygon(polygon);
|
|
|
|
|
|
|
|
if (nativePolygon == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (e.PropertyName == MapElement.StrokeColorProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativePolygon.StrokeColor = polygon.StrokeColor.ToAndroid(Color.Black);
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == MapElement.StrokeWidthProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativePolygon.StrokeWidth = polygon.StrokeWidth;
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == Polygon.FillColorProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativePolygon.FillColor = polygon.FillColor.ToAndroid();
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == nameof(polygon.Geopath))
|
|
|
|
{
|
|
|
|
nativePolygon.Points = polygon.Geopath.Select(p => new LatLng(p.Latitude, p.Longitude)).ToList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddPolygon(Polygon polygon)
|
|
|
|
{
|
|
|
|
var map = NativeMap;
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_polygons == null)
|
|
|
|
{
|
|
|
|
_polygons = new List<APolygon>();
|
|
|
|
}
|
|
|
|
|
|
|
|
var options = CreatePolygonOptions(polygon);
|
|
|
|
var nativePolygon = map.AddPolygon(options);
|
|
|
|
|
|
|
|
polygon.MapElementId = nativePolygon.Id;
|
|
|
|
|
|
|
|
_polygons.Add(nativePolygon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemovePolygon(Polygon polygon)
|
|
|
|
{
|
|
|
|
var native = GetNativePolygon(polygon);
|
|
|
|
|
|
|
|
if (native != null)
|
|
|
|
{
|
|
|
|
native.Remove();
|
|
|
|
_polygons.Remove(native);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
2019-11-05 17:52:34 +03:00
|
|
|
|
2020-01-30 00:38:34 +03:00
|
|
|
#region Circles
|
|
|
|
|
|
|
|
protected virtual CircleOptions CreateCircleOptions(Circle circle)
|
|
|
|
{
|
|
|
|
var opts = new CircleOptions()
|
|
|
|
.InvokeCenter(new LatLng(circle.Center.Latitude, circle.Center.Longitude))
|
|
|
|
.InvokeRadius(circle.Radius.Meters)
|
|
|
|
.InvokeStrokeWidth(circle.StrokeWidth);
|
|
|
|
|
|
|
|
if (!circle.StrokeColor.IsDefault)
|
|
|
|
opts.InvokeStrokeColor(circle.StrokeColor.ToAndroid());
|
|
|
|
|
|
|
|
if (!circle.FillColor.IsDefault)
|
|
|
|
opts.InvokeFillColor(circle.FillColor.ToAndroid());
|
|
|
|
|
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected ACircle GetNativeCircle(Circle circle)
|
|
|
|
{
|
|
|
|
ACircle targetCircle = null;
|
|
|
|
|
|
|
|
if (_circles != null)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < _circles.Count; i++)
|
|
|
|
{
|
|
|
|
var native = _circles[i];
|
|
|
|
if (native.Id == (string)circle.MapElementId)
|
|
|
|
{
|
|
|
|
targetCircle = native;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return targetCircle;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected Circle GetFormsCircle(ACircle circle)
|
|
|
|
{
|
|
|
|
Circle targetCircle = null;
|
|
|
|
|
|
|
|
for (int i = 0; i < Element.MapElements.Count; i++)
|
|
|
|
{
|
|
|
|
var mapElement = Element.MapElements[i];
|
|
|
|
if ((string)mapElement.MapElementId == circle.Id)
|
|
|
|
{
|
|
|
|
targetCircle = mapElement as Circle;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return targetCircle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CircleOnPropertyChanged(Circle formsCircle, PropertyChangedEventArgs e)
|
|
|
|
{
|
|
|
|
var nativeCircle = GetNativeCircle(formsCircle);
|
|
|
|
|
|
|
|
if (nativeCircle == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e.PropertyName == Circle.FillColorProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativeCircle.FillColor = formsCircle.FillColor.ToAndroid();
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == Circle.CenterProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativeCircle.Center = new LatLng(formsCircle.Center.Latitude, formsCircle.Center.Longitude);
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == Circle.RadiusProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativeCircle.Radius = formsCircle.Radius.Meters;
|
|
|
|
}
|
|
|
|
else if (e.PropertyName == MapElement.StrokeColorProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativeCircle.StrokeColor = formsCircle.StrokeColor.ToAndroid();
|
|
|
|
}
|
|
|
|
else if(e.PropertyName == MapElement.StrokeWidthProperty.PropertyName)
|
|
|
|
{
|
|
|
|
nativeCircle.StrokeWidth = formsCircle.StrokeWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddCircle(Circle circle)
|
|
|
|
{
|
|
|
|
var map = NativeMap;
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_circles == null)
|
|
|
|
{
|
|
|
|
_circles = new List<ACircle>();
|
|
|
|
}
|
|
|
|
|
|
|
|
var options = CreateCircleOptions(circle);
|
|
|
|
var nativeCircle = map.AddCircle(options);
|
|
|
|
|
|
|
|
circle.MapElementId = nativeCircle.Id;
|
|
|
|
|
|
|
|
_circles.Add(nativeCircle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveCircle(Circle circle)
|
|
|
|
{
|
|
|
|
var native = GetNativeCircle(circle);
|
|
|
|
|
|
|
|
if (native != null)
|
|
|
|
{
|
|
|
|
native.Remove();
|
|
|
|
_circles.Remove(native);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
2019-11-05 17:52:34 +03:00
|
|
|
void SetUserVisible()
|
|
|
|
{
|
|
|
|
GoogleMap map = NativeMap;
|
|
|
|
if (map == null)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Map.IsShowingUser)
|
|
|
|
{
|
|
|
|
var coarseLocationPermission = ContextCompat.CheckSelfPermission(Context, Manifest.Permission.AccessCoarseLocation);
|
|
|
|
var fineLocationPermission = ContextCompat.CheckSelfPermission(Context, Manifest.Permission.AccessFineLocation);
|
|
|
|
|
|
|
|
if (coarseLocationPermission == Permission.Granted || fineLocationPermission == Permission.Granted)
|
|
|
|
{
|
|
|
|
map.MyLocationEnabled = map.UiSettings.MyLocationButtonEnabled = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Log.Warning("Xamarin.Forms.MapRenderer", "Missing location permissions for IsShowingUser");
|
|
|
|
map.MyLocationEnabled = map.UiSettings.MyLocationButtonEnabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
map.MyLocationEnabled = map.UiSettings.MyLocationButtonEnabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-21 13:38:36 +03:00
|
|
|
void IOnMapReadyCallback.OnMapReady(GoogleMap map)
|
|
|
|
{
|
|
|
|
NativeMap = map;
|
2017-04-12 01:52:04 +03:00
|
|
|
OnMapReady(map);
|
2017-03-21 13:38:36 +03:00
|
|
|
}
|
2017-10-09 23:25:45 +03:00
|
|
|
|
|
|
|
void GoogleMap.IOnCameraMoveListener.OnCameraMove()
|
|
|
|
{
|
|
|
|
UpdateVisibleRegion(NativeMap.CameraPosition.Target);
|
|
|
|
}
|
2016-03-22 23:02:25 +03:00
|
|
|
}
|
2017-04-12 01:52:04 +03:00
|
|
|
}
|