Xamarin.Forms get user location when it change

This project you can find at: https://github.com/officialdoniald/Xamarin.Forms.DetectUserLocationCange

When you need to update the user’s location when it change you can make it in Xamarin.Forms too via DependencyService or using Xamarin.Essentials and create a Timer and get the actual Location per seconds (don’t do that :D).

Before coding, we have to satisfy the users permissons.

Andorid: (https://github.com/officialdoniald/Xamarin.Forms.DetectUserLocationCange/blob/master/Xamarin.Forms.DetectUserLocationCange/Xamarin.Forms.DetectUserLocationCange.Android/Properties/AndroidManifest.xml)

Turn ACCESS_COARSE_LOCATION on.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.Xamarin.Forms.DetectUserLocationCange" android:installLocation="auto">
	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="27" />
	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
	<application android:label="Xamarin.Forms.DetectUserLocationCange.Android"></application>
</manifest>

iOS: (https://github.com/officialdoniald/Xamarin.Forms.DetectUserLocationCange/blob/master/Xamarin.Forms.DetectUserLocationCange/Xamarin.Forms.DetectUserLocationCange.iOS/Info.plist)

    <key>NSLocationAlwaysUsageDescription</key>
    <string>Can we use your location at all times?</string>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Can we use your location when your app is being used?</string>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>Can we use your location at all times?</string>

ATTENTION: if you will publish on the App Store, you have to pay attention for the privacy. You have to ask the user every time before you will get her/his location. So best way to do that, create a user’s settings, where the user can turn in or off, that you get her/his location. If turned off, you have to show a popup with some text: Can we use your location? and then subcribe to the event. If turned on, you don’t have to show popup.

We have to create an interface in the StandardLibrary. (https://github.com/officialdoniald/Xamarin.Forms.DetectUserLocationCange/blob/master/Xamarin.Forms.DetectUserLocationCange/Xamarin.Forms.DetectUserLocationCange/Services/ILocationUpdateService.cs)

using System;

namespace Xamarin.Forms.DetectUserLocationCange.Services
{
    public interface ILocationUpdateService
    {
        void GetUserLocation();
        event EventHandler<ILocationEventArgs> LocationChanged;
    }

    public interface ILocationEventArgs
    {
        double Latitude { get; set; }
        double Longitude { get; set; }
    }
}

We have to implement this interface in the platforms.

Android: (https://github.com/officialdoniald/Xamarin.Forms.DetectUserLocationCange/blob/master/Xamarin.Forms.DetectUserLocationCange/Xamarin.Forms.DetectUserLocationCange.Android/Services/LocationUpdateService.cs)

using System;
using Android.Content;
using Android.Locations;
using Android.OS;
using Android.Runtime;
using Xamarin.Forms;
using Xamarin.Forms.DetectUserLocationCange.Droid.Services;
using Xamarin.Forms.DetectUserLocationCange.Services;

[assembly: Dependency(typeof(LocationUpdateService))]
namespace Xamarin.Forms.DetectUserLocationCange.Droid.Services
{
    public class LocationEventArgs : EventArgs, ILocationEventArgs
    {
        public double Latitude { get; set; }
        public double Longitude { get; set; }
    }

    public class LocationUpdateService : Java.Lang.Object, ILocationUpdateService, ILocationListener
    {
        LocationManager locationManager;

        public void GetUserLocation()
        {
#pragma warning disable CS0618 // Type or member is obsolete
            locationManager = (LocationManager)Forms.Context.GetSystemService(Context.LocationService);
#pragma warning restore CS0618 // Type or member is obsolete
            locationManager.RequestLocationUpdates(
                provider: LocationManager.NetworkProvider,
                minTime: 0,//millisec
                minDistance: 0,//metres
                listener: this);
        }

        ~LocationUpdateService()
        {
            locationManager.RemoveUpdates(this);
        }

        public void OnLocationChanged(Location location)
        {
            if (location != null)
            {
                LocationEventArgs args = new LocationEventArgs
                {
                    Latitude = location.Latitude,
                    Longitude = location.Longitude
                };
                LocationChanged(this, args);
            };
        }

        public event EventHandler<ILocationEventArgs> LocationChanged;
        
        event EventHandler<ILocationEventArgs>
            ILocationUpdateService.LocationChanged
        {
            add
            {
                LocationChanged += value;
            }
            remove
            {
                LocationChanged -= value;
            }
        }

        public void OnProviderDisabled(string provider) { }

        public void OnProviderEnabled(string provider) { }

        public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras) { }
    }
}

iOS: (https://github.com/officialdoniald/Xamarin.Forms.DetectUserLocationCange/blob/master/Xamarin.Forms.DetectUserLocationCange/Xamarin.Forms.DetectUserLocationCange.iOS/Services/LocationUpdateService.cs)

using System;
using CoreLocation;
using Xamarin.Forms.DetectUserLocationCange.iOS.Services;
using Xamarin.Forms.DetectUserLocationCange.Services;

[assembly: Xamarin.Forms.Dependency(typeof(LocationUpdateService))]
namespace Xamarin.Forms.DetectUserLocationCange.iOS.Services
{
    public class LocationEventArgs : EventArgs, ILocationEventArgs
    {
        public double Latitude { get; set; }
        public double Longitude { get; set; }
    }

    public class LocationUpdateService : ILocationUpdateService
    {
        CLLocationManager locationManager;

        public event EventHandler<ILocationEventArgs> LocationChanged;

        event EventHandler<ILocationEventArgs> ILocationUpdateService.LocationChanged
        {
            add
            {
                LocationChanged += value;
            }
            remove
            {
                LocationChanged -= value;
            }
        }

        public void GetUserLocation()
        {
            locationManager = new CLLocationManager
            {
                DesiredAccuracy = CLLocation.AccuracyBest,
                DistanceFilter = CLLocationDistance.FilterNone
            };

            locationManager.LocationsUpdated +=
                (object sender, CLLocationsUpdatedEventArgs e) =>
                {
                    var locations = e.Locations;
                    var strLocation =locations[locations.Length - 1].Coordinate.Latitude.ToString();

                    strLocation = strLocation + "," + locations[locations.Length - 1].Coordinate.Longitude.ToString();

                    LocationEventArgs args = new LocationEventArgs();
                    args.Latitude = locations[locations.Length - 1].Coordinate.Latitude;
                    args.Longitude = locations[locations.Length - 1].Coordinate.Longitude;

                    LocationChanged(this, args);
                };

            locationManager.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs e) =>
            {
                if (e.Status ==
                    CLAuthorizationStatus.AuthorizedWhenInUse)
                {
                    locationManager.StartUpdatingLocation();
                }
            };

            locationManager.RequestWhenInUseAuthorization();
        }

        ~LocationUpdateService()
        {
            locationManager.StopUpdatingLocation();
        }
    }
}

Use theese implementations via DependencyService: (https://github.com/officialdoniald/Xamarin.Forms.DetectUserLocationCange/blob/master/Xamarin.Forms.DetectUserLocationCange/Xamarin.Forms.DetectUserLocationCange/App.xaml.cs)

using System;
using Xamarin.Forms;
using Xamarin.Forms.DetectUserLocationCange.Services;
using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace Xamarin.Forms.DetectUserLocationCange
{
    public partial class App : Application
    {
        public static ILocationUpdateService LocationUpdateService;

        public App()
        {
            InitializeComponent();

            MainPage = new MainPage();

            LocationUpdateService.LocationChanged += LocationUpdateService_LocationChanged; ;
        }

        private void LocationUpdateService_LocationChanged(object sender, ILocationEventArgs e)
        {
            //Here you can get the user's location from "e" -> new Location(e.Latitude, e.Longitude);
            //new Location is from Xamarin.Essentials Location object.
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

Xamarin.Forms change ListView SelectedItemColor

This project you can find at: https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor

We have to create a Custom Renderer for a ViewCell. So let’s create a class in the .NET Standard,/PCL Project:

https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/tree/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor/CustomControl/ListViewCustomViewCell.cs/

We created a property for the SelectedItem’s color. Don’t forget: this enum is a cutom enum, we have to create it:

https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/blob/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor/Helper/Enums.cs

Let’s create the platform specific code.

Android: we have to change the Android’s Theme at runtime via EventHandler.

We have to create a ViewCellRenderer class ( https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/blob/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor.Android/CustomRenderers/CustomViewCellRenderer.cs ):

using System.ComponentModel;
using Android.Content;
using Android.Views;
using Xamarin.Forms;
using Xamarin.Forms.ChangeLvSelectedColor.CustomControl.ListView;
using Xamarin.Forms.ChangeLvSelectedColor.Droid.CustomRenderers;
using Xamarin.Forms.ChangeLvSelectedColor.Helper;
using Xamarin.Forms.Platform.Android;
using static Xamarin.Forms.ChangeLvSelectedColor.Droid.MainActivity;

[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]
namespace Xamarin.Forms.ChangeLvSelectedColor.Droid.CustomRenderers
{
    public class CustomViewCellRenderer : ViewCellRenderer
    {
        protected override global::Android.Views.View GetCellCore(Cell item, global::Android.Views.View convertView, ViewGroup parent, Context context)
        {
            var _cellCore = base.GetCellCore(item, convertView, parent, context);

            return _cellCore;
        }

        protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            base.OnCellPropertyChanged(sender, args);

            var extendedViewCell = (CustomViewCell)sender;

            if (extendedViewCell.SelectedCellColor == ListViewSelectedBackGroundColor.CianBlue)
            {
                AndroidEvents.OnAndroidThemeChangeNeeded_Event(null, Xamarin.Forms.ChangeLvSelectedColor.Droid.Resource.Style.MainCianBlueTheme);
            }
            else if (extendedViewCell.SelectedCellColor == ListViewSelectedBackGroundColor.Normal)
            {
                AndroidEvents.OnAndroidThemeChangeNeeded_Event(null, Xamarin.Forms.ChangeLvSelectedColor.Droid.Resource.Style.MainTheme);
            }
            else if (extendedViewCell.SelectedCellColor == ListViewSelectedBackGroundColor.Transparent)
            {
                AndroidEvents.OnAndroidThemeChangeNeeded_Event(null, Xamarin.Forms.ChangeLvSelectedColor.Droid.Resource.Style.MainTransparentTheme);
            }
        }
    }
}

AndroidEvents is a static class, and in this class we have to create an event ( https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/blob/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor.Android/MainActivity.cs ):

public class AndroidEvents
        {
            public static event EventHandler OnAndroidThemeChangeNeeded;

            public static void OnAndroidThemeChangeNeeded_Event(object sender, int id)
            {
                OnAndroidThemeChangeNeeded?.Invoke(sender, id);
            }
        }

This event invoke the Theme Changing at runtime. We have to call it, when the user interact with the ListView(ViewCell). We have to subscribe on this event in the MainActivity:

protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            AndroidEvents.OnAndroidThemeChangeNeeded += AndroidEvents_OnAndroidThemeChangeNeeded; ;
            LoadApplication(new App());
        }

        private void AndroidEvents_OnAndroidThemeChangeNeeded(object sender, int themeid)
        {
            RunOnUiThread(() => {
                SetTheme(themeid);
            });
        }

Finally, we have to create the Theme Shema in the style.xml (MainCianBlueTheme and MainTransparentTheme):

<?xml version="1.0" encoding="utf-8" ?>
<resources>

  <style name="MainTheme" parent="MainTheme.Base">
  </style>
  <style name="MainCianBlueTheme" parent="MainCianBlueTheme.Base">
  </style>
  <style name="MainTransparentTheme" parent="MainTransparentTheme.Base">
  </style>
  <!-- Base theme applied no matter what API -->
  <style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
    <!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
    <item name="windowNoTitle">true</item>
    <!--We will be using the toolbar so no need to show ActionBar-->
    <item name="windowActionBar">false</item>
    <!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette -->
    <!-- colorPrimary is used for the default action bar background -->
    <item name="colorPrimary">#2196F3</item>
    <!-- colorPrimaryDark is used for the status bar -->
    <item name="colorPrimaryDark">#1976D2</item>
    <!-- colorAccent is used as the default value for colorControlActivated
         which is used to tint widgets -->
    <item name="colorAccent">#FF4081</item>
    <!-- You can also set colorControlNormal, colorControlActivated
         colorControlHighlight and colorSwitchThumbNormal. -->
    <item name="windowActionModeOverlay">true</item>

    <item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
  </style>

  <style name="MainCianBlueTheme.Base" parent="MainTheme">
    <item name="android:colorPressedHighlight">@color/anlistviewSelection</item>
    <item name="android:colorLongPressedHighlight">@color/anlistviewSelection</item>
    <item name="android:colorFocusedHighlight">@color/anlistviewSelection</item>
    <item name="android:colorActivatedHighlight">@color/anlistviewSelection</item>
    <item name="android:activatedBackgroundIndicator">@color/anlistviewSelection</item>
  </style>

  <style name="MainTransparentTheme.Base" parent="MainTheme">
    <item name="android:colorPressedHighlight">@color/transparentlistviewSelection</item>
    <item name="android:colorLongPressedHighlight">@color/transparentlistviewSelection</item>
    <item name="android:colorFocusedHighlight">@color/transparentlistviewSelection</item>
    <item name="android:colorActivatedHighlight">@color/transparentlistviewSelection</item>
    <item name="android:activatedBackgroundIndicator">@color/transparentlistviewSelection</item>
  </style>

  <style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">#FF4081</item>
  </style>
</resources>

and their @color variablesin the colors.xml (listviewSelection, anlistviewSelection, transparentlistviewSelection):

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="launcher_background">#FFFFFF</color>
  <color name="colorPrimary">#3F51B5</color>
  <color name="colorPrimaryDark">#303F9F</color>
  <color name="colorAccent">#FF4081</color>
  <color name="listviewSelection">#f17a0a</color>
  <color name="anlistviewSelection">#40E0D0</color>
  <color name="transparentlistviewSelection">#00000000</color>
</resources>

iOS: we just have to create a platform specific version of the CustomViewCell class, and gain two properties a color (https://github.com/officialdoniald/Xamarin.Forms.ChangeListviewSelectedColor/blob/master/Xamarin.Forms.ChangeLvSelectedColor/Xamarin.Forms.ChangeLvSelectedColor.iOS/CustomRenderer/CustomViewCellRenderer.cs):

using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.ChangeLvSelectedColor.CustomControl.ListView;
using Xamarin.Forms.ChangeLvSelectedColor.iOS.CustomRenderer;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]
namespace Xamarin.Forms.ChangeLvSelectedColor.iOS.CustomRenderer
{
    public class CustomViewCellRenderer : ViewCellRenderer
    {
        public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
        {
            var customViewCell = (CustomViewCell)item;

            var cell = base.GetCell(item, reusableCell, tv);

            cell.SelectedBackgroundView = new UIView { BackgroundColor = GetColor(customViewCell.SelectedCellColor) };

            //You can define a new property in the CustomViewCell class, and you can use it here:
            //This code is set the unselected background color of the ViewCell:
            //cell.BackgroundColor = GetColor(customViewCell.UnSelectedCellColor);

            return cell;
        }

        public UIColor GetColor(Helper.ListViewSelectedBackGroundColor color)
        {
            switch (color)
            {
                case Helper.ListViewSelectedBackGroundColor.CianBlue:
                    return Color.FromHex("#40E0D0").ToUIColor();
                default:
                    return Color.Transparent.ToUIColor();
            }
        }
    }
}

Xamarin.Forms – Android – change the Theme at runtime

This project you can find at: https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime

In the .NET Standard/PCL Project we can’t say that, please change the Theme right now, because wehave to implement some platform specific implementation in the Android project.

How can the two project communicate? Now, we will see another way, unlike the previous ones, we will use events, not dependency service.

So, let’s create our event class in the .NET Standard/PCL Project (https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime/GlobalEvents.cs):

using System;
namespace XamarinFormsChangeAndoirdThemeRuntime
{
public class GlobalEvents
{
public static event EventHandler OnAndroidThemeChangeNeeded;
    
public static void OnAndroidThemeChangeNeeded_Event(object sender, int themeid)
    {
        OnAndroidThemeChangeNeeded?.Invoke(sender, themeid);
    }
   }
}

In the Android site, we will use the SetTheme(themeid) function, that set the Theme on the Application. We have to subscribe int the event int the MainActivity, and we have to call the SetTheme(themeid) method, in the main thread (https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime.Android/MainActivity.cs):

using Android.App;
using Android.Content.PM;
using Android.OS;

namespace XamarinFormsChangeAndoirdThemeRuntime.Droid
{
    [Activity(Label = "XamarinFormsChangeAndoirdThemeRuntime", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

            GlobalVariables.MainThemeResourceID = Resource.Style.MainTheme;
            GlobalVariables.MainTransparentThemeResourceID = Resource.Style.MainTransparentTheme_Base;
            GlobalEvents.OnAndroidThemeChangeNeeded += GlobalEvents_OnAndroidThemeChangeNeeded; ;

            LoadApplication(new App());
        }

        private void GlobalEvents_OnAndroidThemeChangeNeeded(object sender, int themeid)
        {
            RunOnUiThread(() => {
                SetTheme(themeid);
            });
        }
    }
}

As you see, we gain the Theme’s Resource ID to the SetTheme(themeid) function. So we have to store theese Themes, in a global variable. Let’s create a class in the .NET Standard/PCL Project, and define static int variables as the Theme’s IDs (https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime/GlobalVariables.cs):

namespace XamarinFormsChangeAndoirdThemeRuntime
{
    public class GlobalVariables
    {
        public static int MainThemeResourceID { get; set; }

        public static int MainTransparentThemeResourceID { get; set; }
    }
}

And now we have to just try theese codes. Let’s create a Page with two Buttons, and subscribe on their Click events:

https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime/MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinFormsChangeAndoirdThemeRuntime.MainPage">
    <StackLayout>
        <Button x:Name="mainThemeButton" 
                Clicked="MainThemeButton_Clicked" 
                Text="MainTheme"/>
        <Button x:Name="mainTransparentButton" 
                Clicked="MainTransparentButton_Clicked" 
                Text="TransparentTheme"/>
    </StackLayout>
</ContentPage>

https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime/MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace XamarinFormsChangeAndoirdThemeRuntime
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void MainThemeButton_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(() => 
            {
                GlobalEvents.OnAndroidThemeChangeNeeded_Event(null, GlobalVariables.MainThemeResourceID);
            });
        }

        private void MainTransparentButton_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                GlobalEvents.OnAndroidThemeChangeNeeded_Event(null, GlobalVariables.MainTransparentThemeResourceID);
            });
        }
    }
}

I defined two Themes, theese Themes change a listview’s color. You can find they at: https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/tree/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime.Android/Resources/values

Their was defined at the color.xml(link above).

Of cource you don’t have to do it this way, that was an extreme way, you can implement in the Android code, but if you want to use it from the .NET Standard/PCL Project, you have to write an event, or write through dependency service.

Fun fact: this GitHub project’s name is too large, so you can’t Debug it without renaming.

Xamarin.Forms – CustomMasterDetailPage – change navigation icon(back button and “hamburger” menu button) – Android

This project, you can find at: https://github.com/officialdoniald/Xamarin.Forms.CustomControls

We have to create some platforms specific code (custom NavigationPage Renderer), because in the base Xamarin.Forms code, we can’t find this implementation. So first step, we have to create a class in the .NET Standard/PCL project: CustomMasterDetailPage( https://github.com/officialdoniald/Xamarin.Forms.CustomControls/blob/master/XamarinForms.CustomControls/XamarinForms.CustomControls/MasterDetailPage/CustomMasterDetailPage.cs ).

using Xamarin.Forms; 
using XamarinForms.CustomControls.Enums;
namespace XamarinForms.CustomControls.MasterDetailPage
{
public class CustomMasterDetailPage : Xamarin.Forms.MasterDetailPage
{
public CustomMasterDetailPage() : base() { }
}
}

In Xamarin.Android, we can say that: ok, let’s change the back button and the hamburger menu button image forever, so we have to write an algorythm, that will change our icons. We have to watch the NavigationStack, and it’s count is equal to 1, we have to change the icon to a hamburger menu icon, otherwise we have to change the icon to a back button icon. Let’s do it.

So we have to write a MasterDetailPageRenderer class in the Android Project and we have to write the algorythm there.

 using Android.Content;
 using Android.Graphics;
 using Android.Graphics.Drawables;
 using Android.Runtime;
 using Android.Widget;
 using Plugin.CurrentActivity;
 using System;
 using Xamarin.Forms;
 using Xamarin.Forms.Platform.Android.AppCompat;
 using XamarinForms.CustomControls.Droid.CustomRenderer;
 using XamarinForms.CustomControls.MasterDetailPage;

[assembly: ExportRenderer(typeof(CustomMasterDetailPage), typeof(MasterNavigationPageRenderer))]
 namespace XamarinForms.CustomControls.Droid.CustomRenderer
 { 
pragma warning disable CS0618
public class MasterNavigationPageRenderer : MasterDetailPageRenderer
{
    private static Android.Support.V7.Widget.Toolbar GetToolbar() => (CrossCurrentActivity.Current?.Activity as MainActivity)?.FindViewById(Resource.Id.toolbar);

    private Android.Support.V7.Widget.Toolbar toolbar;

    public MasterNavigationPageRenderer() : base() { }

    public MasterNavigationPageRenderer(Context context) : base(context) { }

    public MasterNavigationPageRenderer(IntPtr a, JniHandleOwnership b) : base() { }

    protected override void OnLayout(bool changed, int l, int t, int r, int b)
    {
        base.OnLayout(changed, l, t, r, b);
        toolbar = GetToolbar();

        if (toolbar != null)
        {
            if (GlobalVariables.NavigationStackCount == 1)
            {
                SetNavigationButton(Resource.Drawable.menu);
            }
            else
            {
                SetNavigationButton(Resource.Drawable.back);
            }
        }
    }

    private void SetNavigationButton(int resourceID)
    {
        var icon = Forms.Context.GetDrawable(resourceID);
        using (var drawable = ((BitmapDrawable)icon).Bitmap)
        using (var bitmap = Bitmap.CreateScaledBitmap(drawable, 80, 80, false))
        using (var newDrawable = new BitmapDrawable(Resources, bitmap))
        {
            toolbar.NavigationIcon = newDrawable;
        }
    }
}
pragma warning restore CS0618
}
GlobalVariables.NavigationStackCount is public static variable. You can defined it in the .NET Standard/PCL project.

Next step, we have to create a platform specific NavigationPageRenderer. So let’s create a class in the .NET Standard/PCL project, and call it CustomNavigationPage ( https://github.com/officialdoniald/Xamarin.Forms.CustomControls/blob/master/XamarinForms.CustomControls/XamarinForms.CustomControls/NavigationPage/CustomNavigationPage.cs )

Than we have to create the platform spec. implementation in the Android project (https://github.com/officialdoniald/Xamarin.Forms.CustomControls/blob/master/XamarinForms.CustomControls/XamarinForms.CustomControls.Android/CustomRenderer/CustonNavigationPageRenderer.cs) :

 using System;
 using System.ComponentModel;
 using System.Threading.Tasks;
 using Android.Content;
 using Android.Graphics;
 using Android.Graphics.Drawables;
 using Android.Runtime;
 using Android.Support.V7.Graphics.Drawable;
 using Android.Util;
 using Android.Widget;
 using Plugin.CurrentActivity;
 using Xamarin.Forms;
 using Xamarin.Forms.Platform.Android;
 using XamarinForms.CustomControls.Droid.CustomRenderer;
 using XamarinForms.CustomControls.Enums;
 using XamarinForms.CustomControls.NavigationPage;
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustonNavigationPageRenderer))] 
namespace XamarinForms.CustomControls.Droid.CustomRenderer
 { 
pragma warning disable CS0618
public class CustonNavigationPageRenderer : Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer
{
    #region Properties

    private static Android.Support.V7.Widget.Toolbar GetToolbar() => (CrossCurrentActivity.Current?.Activity as MainActivity)?.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);

    private Android.Support.V7.Widget.Toolbar toolbar;

    private Page view;

    #endregion

    #region Kontruktor

    public CustonNavigationPageRenderer() : base() { }

    public CustonNavigationPageRenderer(Context context) : base(context) { }

    public CustonNavigationPageRenderer(IntPtr a, JniHandleOwnership b) : base() { }

    #endregion

 protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        var page = (CustomNavigationPage)sender;
    }

    protected override void OnLayout(bool changed, int l, int t, int r, int b)
    {
        base.OnLayout(changed, l, t, r, b);

        //You can define special pages, where you can change the rule.
        //if (view is LoginPage || view is PasswordResetPage || view is RegisterPage || view is SMSPage)
        //{
        //    SetIcon();
        //}
    }

    protected override Task<bool> OnPushAsync(Page view, bool animated)
    {
        var retVal = base.OnPushAsync(view, animated);

        GlobalVariables.NavigationStackCount = view.Navigation.NavigationStack.Count;

        this.view = view;

        return retVal;
    }

    protected override Task<bool> OnPopToRootAsync(Page page, bool animated)
    {
        var retVal = base.OnPopToRootAsync(page, animated);

        GlobalVariables.NavigationStackCount = page.Navigation.NavigationStack.Count - 1;

        view = page;

        return retVal;
    }

    protected override Task<bool> OnPopViewAsync(Page page, bool animated)
    {
        var retVal = base.OnPopViewAsync(page, animated);

        GlobalVariables.NavigationStackCount = page.Navigation.NavigationStack.Count - 1;

        view = page;

        return retVal;
    }

    private void SetIcon()
    {
        toolbar = GetToolbar();

        if (toolbar != null)
        {
            if (GlobalVariables.NavigationStackCount == 1)
            {
                SetNavigationButton(Resource.Drawable.menu);
            }
            else
            {
                SetNavigationButton(Resource.Drawable.back);
            }
        }
    }

    private void SetNavigationButton(int resourceID)
    {
        var icon = Forms.Context.GetDrawable(resourceID);
        using (var drawable = ((BitmapDrawable)icon).Bitmap)
        using (var bitmap = Bitmap.CreateScaledBitmap(drawable, 80, 80, false))
        using (var newDrawable = new BitmapDrawable(Resources, bitmap))
        {
            toolbar.NavigationIcon = newDrawable;
        }
    }
}
pragma warning restore CS0618
}

Here the most important thing is to store the GlobalVariables.NavigationStackCount. Here can change the icons too.