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:
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?
You can achieve that with the following Shell custom renderer.
SetColors(TabLayout tabLayout, Color foreground, Color background, Color title, Color unselected)
method are self-explanatory.using Color = Xamarin.Forms.Color;
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;
}
}
}
EDIT
An easier solution without custom renderer?
Take a look at TabView from xamarin-communitytoolkit
package.