Im using Xamarin Forms Maps and I implemented location button:
Map.IsShowingUser = true;
Also I added Permissions (Xamarin Essentials nuget) and implemented like this in my view model:
public class MapViewModel : BaseViewModel
{
public MapViewModel(CustomMap map)
{
Map = map;
GetPermissions();
Task.Run(async () => { await GetImage(); });
}
public void SetPins()
{
if (App.FilterPins != null && App.FilterPins.Count > 0)
{
Device.BeginInvokeOnMainThread(() =>
{
Map.CustomPins.Clear();
Map.CustomPins.AddRange(App.FilterPins);
foreach (var item in App.FilterPins)
{
Map.Pins.Add(item);
App.SelectedPin = item;
item.InfoWindowClicked += Pin_InfoWindowClicked;
}
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
OnPropertyChanged(nameof(Map.CustomPins));
OnPropertyChanged(nameof(Map));
});
}
else
{
GetMapDefaultData();
}
}
public void SetMapToSelectedPin()
{
Device.BeginInvokeOnMainThread(() =>
{
if (App.SelectedPin != null)
{
//gledam da li je u listi pinova App.FilterPins ili u DefaultPins (iz default servisa)
if (Map.CustomPins.Any(x => x.Id == App.SelectedPin.Id))
{
//focusOnPin
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
}
else
{
//add pin to list -> Map.Pins.Add(pin);
//focusonpin
if (App.FilterPins != null && App.FilterPins.Count > 0)
{
Map.CustomPins.Add(App.SelectedPin);
Map.Pins.Add(App.SelectedPin);
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
}
}
}
else
{
Map.MoveToRegion(MapSpan.FromCenterAndRadius(Constants.BelgradeCoordinates, Distance.FromMiles(1.0)));
}
OnPropertyChanged(nameof(Map));
});
}
private async Task GetImage()
{
App.PinImages = new List<PinImageResponseModel>();
var result = await ApiServiceProvider.GetPinImages();
Device.BeginInvokeOnMainThread(() =>
{
App.PinImages = result;
});
}
public CustomPin _pin { get; set; }
public CustomPin Pin
{
get { return _pin; }
set { _pin = value; OnPropertyChanged(); }
}
public ICommand PositionMapOnPinCommand { get; set; }
private async void GetMapDefaultData()
{
try
{
DefaultRegionsAndClassesResponseModel regionsAndPinsResponse = new DefaultRegionsAndClassesResponseModel();
#region Regions
var regions = await ApiServiceProvider.GetRegionsQuery(null, 0, 5000);
//if (regions != null && regions.Data != null)
//{
// var polygon = new Polygon();
// foreach (var region in regions.Data.Where(x => x.Checked).ToList())
// {
// polygon.StrokeWidth = 8;
// polygon.StrokeColor = Color.Green;
// polygon.FillColor = Color.FromRgba(255, 0, 0, 64);
// foreach (var point in region.Points)
// {
// polygon.Geopath.Add(new Position(point.Latitude, point.Longitude));
// }
// Map.MapElements.Add(polygon);
// }
//}
#endregion
#region Pins & Infoboxes
regionsAndPinsResponse = await ApiServiceProvider.GetDefaultRegionsAndClasses();
Device.BeginInvokeOnMainThread(() =>
{
if (regionsAndPinsResponse.Succeeded && regionsAndPinsResponse.Data != null && regionsAndPinsResponse.Data.Count > 0)
{
foreach (var mainItem in regionsAndPinsResponse.Data)
{
CustomPin pin = new CustomPin();
if (mainItem != null && mainItem.Points.Count > 0)
{
pin.Id = mainItem.IdObjectInstance;
pin.ClassId = mainItem.ObjectClassIdObjectClass;
pin.Label = mainItem.ObjectClassName;
pin.IsFavorite = mainItem.IsFavorite.HasValue;
foreach (var item in App.PinImages)
{
if (mainItem.Status != null && mainItem.Status.ClassStatus.ClassStatusIcon != null && item.Name.Equals(mainItem.Status.ClassStatus.ClassStatusIcon))
{
string base64 = item.Base64String.Substring(item.Base64String.IndexOf(',') + 1);
base64 = base64.Trim('\0');
pin.InfoBox.ImageString = base64;
if (pin.InfoBox.ImageString != null)
{
var source = Convert.FromBase64String(pin.InfoBox.ImageString);
pin.InfoBox.PinImageSource = ImageSource.FromStream(() => new MemoryStream(source));
}
}
}
if (mainItem.Points != null)
{
pin.Position = new Position(mainItem.Points.FirstOrDefault().Latitude, mainItem.Points.FirstOrDefault().Longitude);
}
else
{
//add polygon
}
foreach (var item in mainItem.Strings)
{
pin.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo { BoldLabelTitle = item.ClassParameterName + ": ", LabelValue = item.StringValue });
}
foreach (var item in mainItem.Integers)
{
pin.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo { BoldLabelTitle = item.ClassParameterName + ": ", LabelValue = item.IntValue.ToString() });
}
}
pin.InfoWindowClicked += Pin_InfoWindowClicked;
Map.CustomPins.Add(pin);
Map.Pins.Add(pin);
}
}
});
#endregion
}
catch (Exception ex)
{
await Shell.Current.DisplayAlert("Error", "Something went wrong with maps", "OK");
}
}
private void Pin_InfoWindowClicked(object sender, PinClickedEventArgs e)
{
Device.BeginInvokeOnMainThread(async () =>
{
var pin = sender as CustomPin;
App.SelectedPin = pin;
await Shell.Current.Navigation.PushAsync(new ObjectParametersPage());
});
}
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)
{
Map.IsShowingUser = true;
}
else
{
await Shell.Current.DisplayAlert("Permission Denied", "We Need to access your Location. But it is not granted", "OK");
}
}
public CustomMap Map { get; set; }
public ICommand SetCameraToChosenPinCommand { get; set; }
}
My XAML:
</ContentPage>
<ContentPage.Content>
<renderers:CustomMap x:Name="map" IsShowingUser="True"/>
</ContentPage.Content>
</ContentPage>
CodeBehind:
public partial class MapPage : ContentPage
{
MapViewModel mapViewModel;
public MapPage()
{
InitializeComponent();
BindingContext = mapViewModel = new MapViewModel(map);
}
protected override void OnAppearing()
{
base.OnAppearing();
mapViewModel.SetPins();
mapViewModel.SetMapToSelectedPin();
}
}
my CustomMap:
public class CustomMap : Map
{
//public List<CustomPin> CustomPins { get; set; }
public CustomMap()
{
CustomPins = new ObservableCollection<CustomPin>();
CustomPins.CollectionChanged += PinsSourceOnCollectionChanged;
}
public ObservableCollection<CustomPin> CustomPins
{
get { return (ObservableCollection<CustomPin>)GetValue(PinsSourceProperty); }
set { SetValue(PinsSourceProperty, value); OnPropertyChanged(nameof(CustomPins)); }
}
public static readonly BindableProperty PinsSourceProperty = BindableProperty.Create(
propertyName: "PinsSource",
returnType: typeof(ObservableCollection<CustomPin>),
declaringType: typeof(CustomMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
validateValue: null,
propertyChanged: PinsSourcePropertyChanged);
public MapSpan MapSpan
{
get { return (MapSpan)GetValue(MapSpanProperty); }
set { SetValue(MapSpanProperty, value); }
}
public static readonly BindableProperty MapSpanProperty = BindableProperty.Create(
propertyName: "MapSpan",
returnType: typeof(MapSpan),
declaringType: typeof(CustomMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
validateValue: null,
propertyChanged: MapSpanPropertyChanged);
private static void MapSpanPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var thisInstance = bindable as CustomMap;
var newMapSpan = newValue as MapSpan;
thisInstance?.MoveToRegion(newMapSpan);
}
private static void PinsSourcePropertyChanged(BindableObject bindable, object oldvalue, object newValue)
{
var thisInstance = bindable as CustomMap;
var newPinsSource = newValue as ObservableCollection<CustomPin>;
if (thisInstance == null ||
newPinsSource == null)
return;
UpdatePinsSource(thisInstance, newPinsSource);
}
private void PinsSourceOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdatePinsSource(this, sender as IEnumerable<CustomPin>);
}
private static void UpdatePinsSource(CustomMap bindableMap, IEnumerable<CustomPin> newSource)
{
bindableMap.IsShowingUser = true;
bindableMap.Pins.Clear();
foreach (var pin in newSource)
bindableMap.Pins.Add(pin);
}
}
So, I have a bug only on first time installing app on my phone - it doesnt show location button, because its async method. Each next tiem when I open the Map page there is a button.
So, my question would be: how to properly integrate permissions and map, in order to present location button on the first startup of application?