Reputation: 593
I have a bottom TabBar with a Message Icon, that shows a tab(ShellContent) a page with Messages. Now how can I dynamically show numbers on top of the Tabbar icon, example usecase: Display number 2 over Message icon when user has 2 new messages. I just have basic Tab item as below, please suggest how can I dynamically display number on it. I also follow MVVM architecture.
<Tab Title="Inbox" x:Name="messages"
Icon="message.svg">
<ShellContent ContentTemplate="{DataTemplate views:MessagesPage}" Route="messages"/>
</Tab>
Upvotes: 0
Views: 344
Reputation: 13879
You can try to achieve this with custom platform specific shell handlers for Android and iOS.
Please refer to the following code:
On android:
namespace ShellTabbarBadgeMAUI
{
public class TabbarBadgeRenderer : ShellRenderer
{
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
{
//return base.CreateBottomNavViewAppearanceTracker(shellItem);
return new BadgeShellBottomNavViewAppearanceTracker(this, shellItem);
}
}
class BadgeShellBottomNavViewAppearanceTracker : ShellBottomNavViewAppearanceTracker
{
private BadgeDrawable? badgeDrawable;
public BadgeShellBottomNavViewAppearanceTracker(IShellContext shellContext, ShellItem shellItem) : base(shellContext, shellItem)
{
}
public override void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
{
base.SetAppearance(bottomView, appearance);
if (badgeDrawable is null)
{
const int cartTabbarItemIndex = 1;
badgeDrawable = bottomView.GetOrCreateBadge(cartTabbarItemIndex);
UpdateBadge(0);
BadgeCounterService.CountChanged += OnCountChanged;
}
}
private void OnCountChanged(object? sender, int newCount)
{
UpdateBadge(newCount);
}
private void UpdateBadge(int count)
{
if(badgeDrawable is not null)
{
if (count <= 0)
{
badgeDrawable.SetVisible(false);
}
else
{
badgeDrawable.Number = count;
badgeDrawable.BackgroundColor = Colors.Red.ToPlatform();
badgeDrawable.BadgeTextColor = Colors.White.ToPlatform();
badgeDrawable.SetVisible(true);
}
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
BadgeCounterService.CountChanged -= OnCountChanged;
}
}
}
On iOS:
namespace ShellTabbarBadgeMAUI
{
public class TabbarBadgeRenderer : ShellRenderer
{
protected override IShellTabBarAppearanceTracker CreateTabBarAppearanceTracker()
{
//return base.CreateTabBarAppearanceTracker();
return new BadgeShellTabbarAppearanceTracker();
}
}
class BadgeShellTabbarAppearanceTracker : ShellTabBarAppearanceTracker
{
private UITabBarItem? _cartTabbarItem;
public override void UpdateLayout(UITabBarController controller)
{
base.UpdateLayout(controller);
if (_cartTabbarItem is null)
{
const int cartTabbarItemIndex = 1;
_cartTabbarItem = controller.TabBar.Items?[cartTabbarItemIndex];
if (_cartTabbarItem is not null)
{
UpdateBadge(0);
BadgeCounterService.CountChanged += OnCountChanged;
}
}
}
private void OnCountChanged(object? sender, int newCount)
{
UpdateBadge(newCount);
}
private void UpdateBadge(int count)
{
if(_cartTabbarItem is not null)
{
if(count <= 0)
{
_cartTabbarItem.BadgeValue = null;
}
else
{
_cartTabbarItem.BadgeValue = count.ToString();
_cartTabbarItem.BadgeColor = Colors.Red.ToPlatform();
}
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
BadgeCounterService.CountChanged -= OnCountChanged;
}
}
}
In MauiProgram.cs
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.ConfigureMauiHandlers(h=>
{
#if ANDROID || IOS
h.AddHandler<Shell, TabbarBadgeRenderer>();
#endif
});
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
Refer : https://github.com/dotnet/maui/issues/8305#issuecomment-1742160046
Upvotes: 1