如何将位置按钮添加到 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;
}
}
LocationButton
在 Xaml 中定义:<ImageButton x:Name="LocationButton" ... />
==================================更新#2======== =========================
如果需要在ios模拟器中测试位置,您需要手动选择位置。点击模拟器设置如下:
选择一个位置:
我实现了 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;
}
}
LocationButton
在 Xaml 中定义:<ImageButton x:Name="LocationButton" ... />
==================================更新#2======== =========================
如果需要在ios模拟器中测试位置,您需要手动选择位置。点击模拟器设置如下:
选择一个位置: