Skip to content

Instantly share code, notes, and snippets.

@LynoDesu
Created June 20, 2018 19:04
Show Gist options
  • 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>
@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