Xamarin Forms Maps - how to refresh/update the map - CustomMap Renderer

前端 未结 4 2011
予麋鹿
予麋鹿 2021-02-06 14:06

If you are searching for a full polylines, pins, tiles, UIOptions (and 3D effects soon) renderings/implementations, you should take a loot at the public github I made at

4条回答
  •  情话喂你
    2021-02-06 14:26

    Building on these answers, here is what I did to get it to work on iOS. This allows changing the route even after the map is loaded, unlike the Xamarin sample.

    Firstly, custom map class as per @Sven-Michael Stübe with the update from @Emixam23:

    public class CustomMap : Map
    {
        public static readonly BindableProperty RouteCoordinatesProperty =
            BindableProperty.Create(nameof(RouteCoordinates), typeof(List), typeof(CustomMap), new List(), BindingMode.TwoWay);
    
        public List RouteCoordinates
        {
            get { return (List)GetValue(RouteCoordinatesProperty); }
            set { SetValue(RouteCoordinatesProperty, value); }
        }
    
        public CustomMap()
        {
            RouteCoordinates = new List();
        }
    }
    

    Next, the iOS custom renderer:

    [assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
    namespace KZNTR.iOS
    {
        public class CustomMapRenderer : MapRenderer
        {
            MKPolylineRenderer polylineRenderer;
            CustomMap map;
    
            protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
    
                if ((this.Element == null) || (this.Control == null))
                    return;
    
                if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
                {
                    map = (CustomMap)sender;
                    UpdatePolyLine();
                }
            }
    
            [Foundation.Export("mapView:rendererForOverlay:")]
            MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlay)
            {
                if (polylineRenderer == null)
                {
                    var o = ObjCRuntime.Runtime.GetNSObject(overlay.Handle) as MKPolyline;
    
                    polylineRenderer = new MKPolylineRenderer(o);
                    //polylineRenderer = new MKPolylineRenderer(overlay as MKPolyline);
                    polylineRenderer.FillColor = UIColor.Blue;
                    polylineRenderer.StrokeColor = UIColor.Red;
                    polylineRenderer.LineWidth = 3;
                    polylineRenderer.Alpha = 0.4f;
                }
                return polylineRenderer;
            }
    
            private void UpdatePolyLine()
            {
    
                var nativeMap = Control as MKMapView;
    
                nativeMap.OverlayRenderer = GetOverlayRenderer;
    
                CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[map.RouteCoordinates.Count];
    
                int index = 0;
                foreach (var position in map.RouteCoordinates)
                {
                    coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
                    index++;
                }
    
                var routeOverlay = MKPolyline.FromCoordinates(coords);
                nativeMap.AddOverlay(routeOverlay);
            }
        }
    }
    

    And finally, adding a polyline to the map:

                Device.BeginInvokeOnMainThread(() =>
                {
                    customMap.RouteCoordinates.Clear();
    
                    var plist = new List(customMap.RouteCoordinates);
    
                    foreach (var point in track.TrackPoints)
                    {
                        plist.Add(new Position(double.Parse(point.Latitude, CultureInfo.InvariantCulture), double.Parse(point.Longitude, CultureInfo.InvariantCulture)));
                    }
    
                    customMap.RouteCoordinates = plist;
    
                    var firstpoint = (from pt in track.TrackPoints select pt).FirstOrDefault();
                    customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(double.Parse(firstpoint.Latitude, CultureInfo.InvariantCulture), double.Parse(firstpoint.Longitude, CultureInfo.InvariantCulture)), Distance.FromMiles(3.0)));
    
                });
    

    Not sure if this is the best way to do it, or the most efficient, I don't know much about renderers, but it does seem to work.

提交回复
热议问题