如何将位置按钮添加到 xamarin 表单地图

How can I add a location button to xamarin forms maps

我实现了 XF 地图,并添加了来自 XF.Essentials 的权限 在 ANdroid 上很好,但在 iOS 上我看不到位置按钮,在我点击批准权限后?

我还需要添加什么才能看到位置按钮(用户地理位置)?

...
        private async void GetPermissions()
        {
            var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
            if (status != PermissionStatus.Granted)
            { 
                status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
            }
            if (status != PermissionStatus.Granted)
            {
                await Shell.Current.DisplayAlert("Permission Denied", "We Need to access your Location. But it is not granted", "OK");
            }
        }
...

我的 iOS 渲染器

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace OperaMobile.iOS.Renderers
{
    public class CustomMapRenderer : MapRenderer
    {
        UIStackView customPinView;
        ObservableCollection<CustomPin> customPins;

        protected override void OnElementChanged(ElementChangedEventArgs<View> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                var nativeMap = Control as MKMapView;
                nativeMap.GetViewForAnnotation = null;
                nativeMap.CalloutAccessoryControlTapped -= OnCalloutAccessoryControlTapped;
                nativeMap.DidSelectAnnotationView -= OnDidSelectAnnotationView;
                nativeMap.DidDeselectAnnotationView -= OnDidDeselectAnnotationView;
            }

            if (e.NewElement != null)
            {
                var formsMap = (CustomMap)e.NewElement;
                var nativeMap = Control as MKMapView;
                customPins = formsMap.CustomPins;

                nativeMap.GetViewForAnnotation = GetViewForAnnotation;
                nativeMap.CalloutAccessoryControlTapped += OnCalloutAccessoryControlTapped;
                nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
                nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;
            }
        }

        protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
        {
            MKAnnotationView annotationView = null;

            if (annotation is MKUserLocation)
                return null;

            var customPin = GetCustomPin(annotation as MKPointAnnotation);
            if (customPin == null)
            {
                throw new Exception("Custom pin not found");
            }

            annotationView = mapView.DequeueReusableAnnotation(customPin.Label);
            if (annotationView == null)
            {
                annotationView = new CustomMKAnnotationView(annotation, customPin.Label);
                annotationView.Image = UIImage.FromFile("pin.png");
                annotationView.CalloutOffset = new CGPoint(0, 0);

                UIImageView uIImageView = new UIImageView(UIImage.FromFile("monkey.png"));
                uIImageView.Frame = new CGRect(0, 0, 75, 100);
                annotationView.LeftCalloutAccessoryView = uIImageView;

                //annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
                //annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
                ((CustomMKAnnotationView)annotationView).Name = customPin.Label;
                //((CustomMKAnnotationView)annotationView).Url = customPin.Url;

                customPinView = new UIStackView();

                foreach (var item in customPin.InfoBox.DetailsObjectInfos)
                {
                    var label = new UILabel();
                    label.Text = item.BoldLabelTitle + item.LabelValue;
                    label.BackgroundColor = UIColor.White;
                    label.Font.WithSize(36);
                    customPinView.AddArrangedSubview(label);
                }
            
                customPinView.Frame = new CGRect(0, 0, 300, 84);
                customPinView.Axis = UILayoutConstraintAxis.Vertical;
                customPinView.Distribution = UIStackViewDistribution.EqualSpacing;
                customPinView.Spacing = 1;
                customPinView.Alignment = UIStackViewAlignment.Fill;
                annotationView.DetailCalloutAccessoryView = customPinView;

                UITapGestureRecognizer tapGestureRecognizer = new
        UITapGestureRecognizer((gesture) =>
        {

                        Shell.Current.GoToAsync(Routes.ObjectParametersPage);

        });
                annotationView.DetailCalloutAccessoryView.AddGestureRecognizer(tapGestureRecognizer);

            }
            annotationView.CanShowCallout = true;

            return annotationView;
        }

        protected virtual void OnCalloutAccessoryControlTapped(object sender, MKMapViewAccessoryTappedEventArgs e)
        {
            Shell.Current.GoToAsync(Routes.ObjectParametersPage);
            //(App.Current as App).NavigationPage.Navigation.PushAsync(new ContentPage());
        }

        void OnDidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)
        {
            CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
            
        }

        void OnDidDeselectAnnotationView(object sender, MKAnnotationViewEventArgs e)
        {
            if (!e.View.Selected)
            {
                customPinView.RemoveFromSuperview();
                customPinView.Dispose();
                customPinView = null;
            }
        }

        CustomPin GetCustomPin(MKPointAnnotation annotation)
        {
            var position = new Position(annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
            foreach (var pin in customPins)
            {
                if (pin.Position == position)
                {
                    return pin;
                }
            }
            return null;
        }
}}

不确定如何在您的项目中添加位置按钮,也许您可​​以在 Xaml[= 中添加带有位置图标的自定义 ImageButton 48=].

Xaml代码:

<RelativeLayout>
    <local:CustomMap x:Name="customMap" 
                     IsShowingUser="True"
                     MapType="Street"
                     IsVisible="true"
                     RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
                         Property=Width,
                         Factor=0,
                         Constant=0}"
                     RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
                         Property=Height,
                         Factor=0,
                         Constant=0}"
                     RelativeLayout.WidthConstraint="{ConstraintExpression
        Type=RelativeToParent,Property=Width,Factor=1,Constant=0}"
                     RelativeLayout.HeightConstraint="{ConstraintExpression
        Type=RelativeToParent,Property=Height,Factor=1,Constant=0}" />
    <ImageButton Source="location.png"
            Clicked="Button_Clicked"
            RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
                         Property=Width,
                         Factor=0.6,
                         Constant=100}"
            RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
                         Property=Height,
                         Factor=0.8,
                         Constant=80}" />
</RelativeLayout>

contentpage.cs :

private async void Button_Clicked(object sender, System.EventArgs e)
{
    var request = new GeolocationRequest(GeolocationAccuracy.Medium);
    var location = await Geolocation.GetLocationAsync(request);

    if (location != null)
    {
        Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
 
    }
       
    customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(location.Latitude, -location.Longitude), Distance.FromMiles(1.0)));
}

效果:

==================================更新 #1======== =========================

在 xamarin forms 中,您可以仅在 Android 中隐藏 xaml 位置按钮,然后 iOS 将显示 xaml 位置按钮。

protected override void OnAppearing()
{
    base.OnAppearing();
    if(Device.RuntimePlatform == "Android")
    {
        LocationButton.IsVisible = false;
    }
}

LocationButtonXaml 中定义:<ImageButton x:Name="LocationButton" ... />

==================================更新#2======== =========================

如果需要在ios模拟器中测试位置,您需要手动选择位置。点击模拟器设置如下:

选择一个位置: