How can I customize the appearance of top tabs (ShellSection) in Xamarin Shell?

2.1k Views Asked by At

I’ve done a lot of research:

However, I couldn’t find how to implement what I have in mind correctly.

My application uses Xamarin Shell with a flyout menu, and some of the pages present a top tab bar. To give you an example, my application looks like this:

enter image description here

Xamarin Shell provides a simple way to create these multi-tabs pages. Now, I want to customize these tabs and change the font, the color of the selection indicator, and so on. In the beginning, I thought I could just create a specific style in the styles.xml file of my Android project and reference it in android.support.design.widget.TabLayout. To give you an example, I did something like this in the Tabbar.xml file inside the Android project of my Xamarin solution:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/sliding_tabs"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="?attr/colorPrimary"
   android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
   app:tabIndicatorColor="@android:color/white"
   style="@style/MyCustomTabLayout"
   app:tabGravity="fill"
   app:tabMode="fixed" />

and this inside the styles.xml file always inside the Android project of the solution:

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <style name="MainTheme" parent="MainTheme.Base">
    <item name="android:textAllCaps">false</item>
  </style>

  <style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
    <item name="tabIndicatorColor">#FFFFFF</item>
    <item name="tabIndicatorHeight">3dp</item>
    <item name="tabSelectedTextColor">#FFFFFF</item>
  </style>
</resources>

However, nothing happened, and the style wasn’t applied. I thought it was a misunderstanding of how to really implement what I had in mind, and I thought that maybe the "sub" top tab bar wasn’t considered a true TabLayout, since it was just a product of ShellSection. In the end, I found that maybe what I needed was a custom renderer. I’m on my way to implement it, but I’m stuck on this issue: I don’t understand how to set the appearance of the ShellSection. My current code for the custom renderer is this:

[assembly: ExportRenderer(typeof(AppShell), typeof(CustomShellRenderer))]
namespace A {
    internal class CustomShellRenderer : ShellRenderer {
        public CustomShellRenderer(Context context) : base(context) { }

        protected override IShellSectionRenderer CreateShellSectionRenderer(ShellSection shellSection) {
            return new CustomShellSectionAppearance(this);
        }
    }

    class CustomShellSectionAppearance : ShellSectionRenderer {
        public Fragment Fragment { get; }
        public event EventHandler AnimationFinished;
        public void Dispose() {
            throw new NotImplementedException();
        }

        public ShellSection ShellSection { get; set; }

        public CustomShellSectionAppearance(IShellContext shellContext) : base(shellContext) { }

        // I thought I need to make my customization here, but it was only a guess:
        // I found nobody talking about customizing a ShellSection on the Web
        protected override void SetAppearance(ShellAppearance appearance) {
            base.SetAppearance(appearance);
            appearance.TabBarDisabledColor = Color.Aqua; // ERROR: appearance has only "get" properties
        }
    }
}

Am I missing something in the process of customizing the appearance of the top tab bar of my Xamarin application?

2

There are 2 best solutions below

1
Cfun On BEST ANSWER

You can achieve that with the following Shell custom renderer.

  • For colors: the parameters names of SetColors(TabLayout tabLayout, Color foreground, Color background, Color title, Color unselected) method are self-explanatory.
  • If Color type is not precede by a namespace in below code then it is from XF, because of using Color = Xamarin.Forms.Color;
  • For Font you need to create a custom view and define whatever attributes you want.
  • You may modify an attribute, change style or do any logic when selection changed using TabSelected and TabUnSelected events, in my demo I am applying bold on text and make it bigger when tab is selected and reverting back when tab is unselected, you may implement a nice animation there also.
public class MyShellRenderer : ShellRenderer
{
    public MyShellRenderer(Context context) : base(context)
    {
    }

    protected override IShellTabLayoutAppearanceTracker CreateTabLayoutAppearanceTracker(ShellSection shellSection)
        => new MyTabLayoutAppearanceTracker(this);
}


public class MyTabLayoutAppearanceTracker : ShellTabLayoutAppearanceTracker
{
    public MyTabLayoutAppearanceTracker(IShellContext shellContext) : base(shellContext)
    {
    }

    public override void SetAppearance(TabLayout tabLayout, ShellAppearance appearance)
    {
        base.SetAppearance(tabLayout, appearance);
        tabLayout.TabSelected += TabLayout_TabSelected;
        tabLayout.TabUnselected += TabLayout_TabUnselected;

        for (var i = 0; i < tabLayout.TabCount; i++)
        {
            TabLayout.Tab tab = tabLayout.GetTabAt(i);
            if (tab.CustomView == null)
            {
                TextView textview = new TextView(Android.App.Application.Context)
                {
                    Text = tabLayout.GetTabAt(i).Text,
                    TextSize = 20,
                    Typeface = Typeface.DefaultBold
                };
                textview.SetTextColor(Android.Graphics.Color.Black);
                tab.SetCustomView(textview);
            }
        }
        base.SetColors(tabLayout, Color.Red, Color.Yellow, Color.Black, Color.Gray);
    }
        private void TabLayout_TabUnselected(object sender, TabLayout.TabUnselectedEventArgs e)
        {
            if (e.Tab?.CustomView is TextView textView)
            {
                textView.Typeface = Typeface.Default;
                textView.TextSize = 15;
            }
        }

        private void TabLayout_TabSelected(object sender, TabLayout.TabSelectedEventArgs e)
        {
            if (e.Tab?.CustomView is TextView textView)
            {
                textView.Typeface = Typeface.DefaultBold;
                textView.TextSize = 20;
            }
        }
}

enter image description here


EDIT

An easier solution without custom renderer?

Take a look at TabView from xamarin-communitytoolkit package.

1
AudioBubble On

If you want to change the colour of the selected tab without the hassle of custom renderers you can do this by editing the Shell Tab's ShellUnselectedColor, ShellTitleColor, and ShellForegroundColor:

  <Style x:Key="BaseStyle"
                   TargetType="Element">
                <Setter Property="Shell.BackgroundColor"
                        Value="{StaticResource Primary}" />
                <Setter Property="Shell.ForegroundColor"
                        Value="White" />
                <Setter Property="Shell.TitleColor"
                        Value="White" />
                <Setter Property="Shell.DisabledColor"
                        Value="#B4FFFFFF" />
                <Setter Property="Shell.UnselectedColor"
                        Value="#95FFFFFF" />
                <Setter Property="Shell.TabBarBackgroundColor"
                        Value="{StaticResource Primary}" />
                <Setter Property="Shell.TabBarForegroundColor"
                        Value="White" />
                <Setter Property="Shell.TabBarUnselectedColor"
                        Value="#95FFFFFF" />
                <Setter Property="Shell.TabBarTitleColor"
                        Value="White" />
            </Style>