Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@LynoDesu
Created June 20, 2018 19:04
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save LynoDesu/64904b6d143892cf14a60a32798a36bb to your computer and use it in GitHub Desktop.
Save LynoDesu/64904b6d143892cf14a60a32798a36bb to your computer and use it in GitHub Desktop.
Disable ShiftMode in Xamarin.Forms Android BottomNavigationView
using System;
using Android.Support.Design.Internal;
using Android.Support.Design.Widget;
namespace MyProject.App.Droid.Helpers
{
public static class AndroidHelpers
{
public static void SetShiftMode(this BottomNavigationView bottomNavigationView, bool enableShiftMode, bool enableItemShiftMode)
{
try
{
var menuView = bottomNavigationView.GetChildAt(0) as BottomNavigationMenuView;
if (menuView == null)
{
System.Diagnostics.Debug.WriteLine("Unable to find BottomNavigationMenuView");
return;
}
var shiftMode = menuView.Class.GetDeclaredField("mShiftingMode");
shiftMode.Accessible = true;
shiftMode.SetBoolean(menuView, enableShiftMode);
shiftMode.Accessible = false;
shiftMode.Dispose();
for(int i = 0; i < menuView.ChildCount; i++)
{
var item = menuView.GetChildAt(i) as BottomNavigationItemView;
if (item == null)
continue;
item.SetShiftingMode(enableItemShiftMode);
item.SetChecked(item.ItemData.IsChecked);
}
menuView.UpdateMenuView();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Unable to set shift mode: {ex}");
}
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace MyProject.App.Controls
{
public class BottomNavTabPage : TabbedPage
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android.AppCompat;
using View = Android.Views.View;
[assembly: ExportRenderer(typeof(BottomNavTabPage), typeof(BottomNavTabPageRenderer))]
namespace MyProject.App.Droid.Renderers
{
public class BottomNavTabPageRenderer : TabbedPageRenderer
{
private bool _isShiftModeSet;
public BottomNavTabPageRenderer(Context context)
: base(context)
{
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
try
{
if (!_isShiftModeSet)
{
var children = GetAllChildViews(ViewGroup);
if (children.SingleOrDefault(x => x is BottomNavigationView) is BottomNavigationView bottomNav)
{
bottomNav.SetShiftMode(false, false);
_isShiftModeSet = true;
}
}
}
catch (Exception e)
{
Console.WriteLine($"Error setting ShiftMode: {e}");
}
}
private List<View> GetAllChildViews(View view)
{
if (!(view is ViewGroup group))
{
return new List<View> {view };
}
var result = new List<View>();
for (int i = 0; i < group.ChildCount; i++)
{
var child = group.GetChildAt(i);
var childList = new List<View> {child};
childList.AddRange(GetAllChildViews(child));
result.AddRange(childList);
}
return result.Distinct().ToList();
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<controls:BottomNavTabPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:MyProject.App.Views;assembly=MyProjects.App"
xmlns:controls="clr-namespace:MyProject.App.Controls;assembly=MyProjects.App"
x:Class="MyProject.App.Views.MainTabPage"
Title="">
<views:NewsFeed></views:NewsFeed>
<views:Rewards></views:Rewards>
<views:Nominations></views:Nominations>
<views:Notifications></views:Notifications>
</controls:BottomNavTabPage>
@greenec
Copy link

greenec commented Jun 22, 2018

I managed to work it out using the following:

<controls:BottomNavTabPage.Children>
        <NavigationPage Icon="social.png" Title="Social">
            <x:Arguments>
                <views:SocialNewsDetail />
            </x:Arguments>
        </NavigationPage>

        <NavigationPage Icon="links.png" Title="Links">
            <x:Arguments>
                <views:NavigationLinksDetail />
            </x:Arguments>
        </NavigationPage>

        <NavigationPage Icon="messages.png" Title="Messages">
            <x:Arguments>
                <views:MessagesDetail />
            </x:Arguments>
        </NavigationPage>

        <NavigationPage Icon="settings.png" Title="Settings">
            <x:Arguments>
                <views:SettingsDetail />
            </x:Arguments>
        </NavigationPage>
</controls:BottomNavTabPage.Children>

Thanks for the great sample!

@LynoDesu
Copy link
Author

No problem, glad it was able to help you and sorry that I didn't reply, I didn't get any notification that you commented on the code!

It looks like you already found the answer, but you can also set it in the actual code of the page if you wanted like this:

<?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="MyProject.App.Views.Rewards"
             Icon="RewardIcon.png">

@cassionandi
Copy link

Thank you for sharing this. Worked like a charm!

@swapnil591
Copy link

Error on below line
bottomNav.SetShiftMode(false, false);

'BottomNavigationView' does not contain a definition for 'SetShiftMode' and no extension method 'SetShiftMode' accepting a first argument of type 'BottomNavigationView' could be found (are you missing a using directive or an assembly reference?)

@JoacimWall
Copy link

JoacimWall commented Nov 14, 2018

Hi i also get

bottomNav.SetShiftMode(false, false);

'BottomNavigationView' does not contain a definition for 'SetShiftMode' and no extension method 'SetShiftMode' accepting a first argument of type 'BottomNavigationView' could be found (are you missing a using directive or an assembly reference?)
Change this
bottomNav.SetShiftMode(false, false);
to
Helpers.AndroidHelpers.SetShiftMode(bottomNav, false, false);

@aman720gupta
Copy link

Thanks This made my day

@James-Aidoo
Copy link

item.SetShiftingMode(enableItemShiftMode);

"'BottomNavigationItemView' does not contain a definition for 'SetShiftingMode' and no accessible extension method 'SetShiftingMode' accepting a first argument of type 'BottomNavigationItemView' could be found (are you missing a using directive or an assembly reference?)"

I get the above error in the AndroidHelpers Class.. What am I doing wrong please

@gsauzet
Copy link

gsauzet commented Mar 22, 2019

Not sure why, but if you get Field "mShiftingMode" not found you can bypass it by modifying the "labelVisibilityMode" directly:

    var declaredFields = menuView.Class.GetDeclaredFields();
    if (declaredFields.Any(t => t.Name == "mShiftingMode"))
    {
        var shiftMode = menuView.Class.GetDeclaredField("mShiftingMode");
        shiftMode.Accessible = true;
        shiftMode.SetBoolean(menuView, enableShiftMode);
        shiftMode.Accessible = false;
        shiftMode.Dispose();
    }
    else
    {
        var visibilityMode = menuView.Class.GetDeclaredField("labelVisibilityMode");
        visibilityMode.Accessible = true;
        visibilityMode.SetInt(menuView, 1);
        visibilityMode.Accessible = false;
        visibilityMode.Dispose();
    }

Edit: 1 is constant value for: LABEL_VISIBILITY_SELECTED
Ref: https://developer.android.com/reference/com/google/android/material/bottomnavigation/LabelVisibilityMode.html#LABEL_VISIBILITY_LABELED

@JimmyPun610
Copy link

James-Aidoo Please read this.
https://stackoverflow.com/questions/51342200/cannot-resolve-method-setshiftingmodeboolean-in-bottomnavigationview/51342426

You may be using 28.0.0.1 Android Support package

@sergey19941201
Copy link

sergey19941201 commented Aug 23, 2019

This helped me in Xamarin native android
<android.support.design.widget.BottomNavigationView
app:labelVisibilityMode="unlabeled"

@InnovativeTechies
Copy link

item.SetShiftingMode(enableItemShiftMode);

"'BottomNavigationItemView' does not contain a definition for 'SetShiftingMode' and no accessible extension method 'SetShiftingMode' accepting a first argument of type 'BottomNavigationItemView' could be found (are you missing a using directive or an assembly reference?)"

I get the above error in the AndroidHelpers Class.. What am I doing wrong please

Use item.SetShifting(enableItemShiftMode);

@abhcr
Copy link

abhcr commented May 29, 2021

Hi i also get

bottomNav.SetShiftMode(false, false);

'BottomNavigationView' does not contain a definition for 'SetShiftMode' and no extension method 'SetShiftMode' accepting a first argument of type 'BottomNavigationView' could be found (are you missing a using directive or an assembly reference?)
Change this
bottomNav.SetShiftMode(false, false);
to
Helpers.AndroidHelpers.SetShiftMode(bottomNav, false, false);

Aren't you supposed to just include the namespace of the extension class ? In this case, "using MyProject.App.Droid.Helpers;" . This will let Visual Studio automatically resolve the extension method from the AndroidHelpers class. That's how extensions are to be used.

@abhcr
Copy link

abhcr commented May 30, 2021

FYI
var shiftMode = menuView.Class.GetDeclaredField("mShiftingMode");
This property is not accessible if pro guard obfuscates it. Either edit the pro guard configuration, or just comment it out. The code just below it where each child contents in the tab has item.SetShifting(false) -> will solve the issue for most. In such cases, the swipe from edges will still allow tab switching, but not swipe inside the content. I found that optimal in my use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment