Search code examples
c#.net-mauicustom-renderer.net-maui.shell

Shell Custom Renderer reset color set by TabBarUnselectedColor


I have a .Net MAUI app that uses Shell TabBar:

<TabBar>
    <Tab Title="Home" Icon="{StaticResource IconHome}">
        <ShellContent ContentTemplate="{DataTemplate local:MainPage}" />
    </Tab>
    <Tab Title="Coverage&#10;Calculator" Icon="{StaticResource IconCalculator}" >
        <ShellContent ContentTemplate="{DataTemplate calculator:CoverageCalculatorPage}" />
    </Tab>
    <Tab Title="Distributor&#10;Locator" Icon="{StaticResource IconLocator}">
        <ShellContent ContentTemplate="{DataTemplate locator:DistributorsLocatorPage}" />
    </Tab>
    <Tab Title="Scan&#10;QR Code" Icon="{StaticResource IconQrScanner}">
        <ShellContent ContentTemplate="{DataTemplate qrScanner:QrScannerPage}" />
    </Tab>        
    <Tab Title="More" Icon="{StaticResource IconMore}">
        <ShellContent ContentTemplate="{DataTemplate more:MoreFeaturesPage}" />
    </Tab>
</TabBar>

The icon color is set in Styles.xaml like this:

        <Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource LaticreteColor}, Dark={StaticResource LaticreteColor}}" />

Here is how the TabBar looks:

enter image description here

As my tabs needed more than one line of text, I applied a custom renderer for Android:

internal class LaticreteShellRenderer : ShellRenderer
{
    public LaticreteShellRenderer(Context context) : base(context) { }
    protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
    {
        return new LaticreteTabLayout();
    }
    public class LaticreteTabLayout : Java.Lang.Object, IShellBottomNavViewAppearanceTracker
    {
        public void ResetAppearance(BottomNavigationView bottomView)
        {
            throw new NotImplementedException();
        }

        public override void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
        {
            bottomView.SetMinimumHeight(180);

            var bottomNavView = bottomView.GetChildAt(0) as BottomNavigationMenuView;

            for (int i = 0; i < bottomNavView.ChildCount; i++)
            {
                var item = bottomNavView.GetChildAt(i) as BottomNavigationItemView;
                var itemTitle = item.GetChildAt(1);
                TextView smallTextView = (TextView)((BaselineLayout)itemTitle).GetChildAt(0);
                TextView largeTextView = (TextView)((BaselineLayout)itemTitle).GetChildAt(1);
                smallTextView.SetLines(2);
                largeTextView.SetLines(2);
            }
        }

This resets the tab's color:

enter image description here

I found that I can change the text color in the custom renderer like this:

                    smallTextView.SetTextColor(global::Android.Graphics.Color.Brown);
                largeTextView.SetTextColor(global::Android.Graphics.Color.Brown);

But I still don't know how to set the icon color, and how I can refer to my custom color set in App.xaml or Colors.xaml.

Why is TabBarUnselectedColor reset, and how can this be fixed?


Solution

  • The attached property TabBarUnselectedColor that you set is not applied because you have overrode the method responsible on doing so SetAppearance().

    This can be fixed by simply calling that method from the base class at the begining like below:

    public void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
    {
        base.SetAppearance(bottomView, appearance);
        bottomView.SetMinimumHeight(180);
        ...
     }
    

    Edit (full code)

    no suitable method found to override"

    internal class LaticreteShellRenderer : ShellRenderer
    {
        public LaticreteShellRenderer(Context context) : base(context) { }
    
        protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
        {
            return new LaticreteTabLayout(this, shellItem);
        }
    }
    
        public class LaticreteTabLayout : ShellBottomNavViewAppearanceTracker
        {
    
        public LaticreteTabLayout (IShellContext shellContext, ShellItem shellItem) : base(shellContext, shellItem)
        {
        }
            public override void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
            {
                base.SetAppearance(bottomView, appearance);
    
                bottomView.SetMinimumHeight(180);
    
                var bottomNavView = bottomView.GetChildAt(0) as BottomNavigationMenuView;
    
                for (int i = 0; i < bottomNavView.ChildCount; i++)
                {
                    var item = bottomNavView.GetChildAt(i) as BottomNavigationItemView;
                    var itemTitle = item.GetChildAt(1);
                    TextView smallTextView = (TextView)((BaselineLayout)itemTitle).GetChildAt(0);
                    TextView largeTextView = (TextView)((BaselineLayout)itemTitle).GetChildAt(1);
                    smallTextView.SetLines(2);
                    largeTextView.SetLines(2);
                }
            }
        }