Closed Dresel closed 1 year ago
Sounds great to me! @davidortinau @pauldipietro Anything to add?
I have started implementation for bottom tabs support (see fork), because this will cover most needs and is the easiest to implement.
How should I proceed? Should I go for a PR? Do you want to refine specification or implementation details?
Android
iOS
@Dresel can you create a draft PR against your fork and then we can check it out?
Feel free to test.
Little dot mode might be looking something like this (Android):
Badge support shouldn't be limited to only Tabs (top or bottom) - it should also be supported in the FlyoutMenu itself so the badges can be seen when the flyout opens and users don't need to navigate into each page to see the badges.
Badge support shouldn't be limited to only Tabs (top or bottom) - it should also be supported in the FlyoutMenu itself so the badges can be seen when the flyout opens and users don't need to navigate into each page to see the badges.
Yes, it's on my (extended) list, might look similar to
Since Flyout Items are rendered with forms controls and can use custom templates, it's (from an implementations perspective) different though. I will update the spec according to that soon.
Can we please have this for non Shell too? I am thinking that it should be first implemented in the non Shell (classic) and then surfaced in Shell.
If we start having having feature discrepancies between Shell and non-Shell that doesn’t sound good to me. I am referring to only features like this one, obviously not everything can or should be in non Shell, that’s the reason why Shell exists.
Can we please have this for non Shell too? I am thinking that it should be first implemented in the non Shell (classic) and then surfaced in Shell.
If we start having having feature discrepancies between Shell and non-Shell that doesn’t sound good to me. I am referring to only features like this one, obviously not everything can or should be in non Shell, that’s the reason why Shell exists.
What's wrong with packages like xamarin-forms-tab-badge? Problem with shell is that it's not possible to use this libraries without touching / replacing too much of the shell internals, that's why I was proposing this in the first place.
My suggestion is not related to that package, it might be a great package. I was only suggesting a way I think it's best to handle this, which is to give this new feature to non-Shell apps too. I just wanted to share my feedback, your proposal is great.
Spec updated.
This is great! Hopefully it's available in pre-release soon
Yep, for our app to be able to continue to use the new Shell, this is a must! Thanks, and waiting anxiously!
Yep, for our app to be able to continue to use the new Shell, this is a must! Thanks, and waiting anxiously!
Also for our app! This is highly requested from the business side
when will the badge for shell appear in xamarin forms? Can you show an example of a renderer for Tab (ShellSection) with badge?
I'm currently waiting for review / feedback from the XF team, I cannot tell you when this will be ready.
Can you show an example of a renderer for Tab (ShellSection) with badge?
If you want you can build the XF repo and play with the Control Gallery sample or check the PR sources.
@Dresel do you have an ETA when badge support within toolbar and flyout menu will be available? We're released a Xamarin based app and user engagement is being impacted by the lack of badges. In-app badges are essential for all modern apps and I'm surprised that this feature is not getting prioritized on the Xamarin team. Thanks and looking forward to your feedback.
@Dresel do you have an ETA when badge support within toolbar and flyout menu will be available? We're released a Xamarin based app and user engagement is being impacted by the lack of badges. In-app badges are essential for all modern apps and I'm surprised that this feature is not getting prioritized on the Xamarin team. Thanks and looking forward to your feedback.
PR is ready for review - hopefully soon 👍
When is this going to be released?
When is this going to be released?
I'm currently waiting for review. I don't know how work items are prioritized, maybe @samhouts can tell you more.
I'm pretty sure you have a team of testers ready to check it out, myself included.
When is this going to be released?
I'm currently waiting for review. I don't know how work items are prioritized, maybe @samhouts can tell you more.
@samhouts will this be included anytime soon? Been waiting on this for awhile since switching to AppShell! It's pretty much expected in apps to have a red badge on a tab icon for notifications....
We're still reviewing the PR. We hope to have it ready soon! Thanks for your patience!
Hello @samhouts really this is an urgent in our software , I hope it will be applied so soon Thank you
Hello. +1 assigning to the priority of this feature. It's a "must-have" thing for Xamarin.Forms development with the help of Shell.
What does "ready soon" mean? I don't know why this takes so long, it's open for more than a year now and a very basic feature. I hope it will be really ready soon ...
+1
vNext+1 means 4.8.0? have it done in 4.8.0, please.
Im really waiting for this feature! Thanks @Dresel
I'm also waiting for this feature.
June 2020, 13 months later, but Xamarin still doesn't supports badge on Shell tabs.... I know it's not your fault, but please @samhouts update us about this release, all my customers needs this feature. Thanks.
when can it be used?
FYI as a workaround, I've managed to get the badges working on iOS and Android on tabs / shells via renderers. Maybe you can use some of this code for yourself..
Android
[assembly: ExportRenderer(typeof(Shell), typeof(CustomShellRenderer))]
namespace Xamarin.Droid.Renderers
{
/// <summary>
/// The CustomShellRenderer is necessary in order to replace the ShellItemRenderer with your own.
/// </summary>
class CustomShellRenderer : ShellRenderer
{
public CustomShellRenderer(Context context) : base(context)
{ }
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
{
return new CustomShellBottomAppearance(this);
}
}
}
Then the CustomShellBottomAppearance.cs:
namespace Xamarin.Droid.Renderers
{
internal class CustomShellBottomAppearance : IShellBottomNavViewAppearanceTracker
{
public CustomShellBottomAppearance(CustomShellRenderer shellRenderer)
{ }
public void Dispose()
{ }
public void ResetAppearance(BottomNavigationView bottomView)
{ }
public async void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
{
bottomView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilitySelected;
var _bottomNavigationMenuView = (BottomNavigationMenuView)bottomView.GetChildAt(0);
var badge = await MainViewModel.CheckNewEventsAsync();
CreatePageBadge(2, badge > 0, badge, _bottomNavigationMenuView);
}
private void CreatePageBadge(int index, bool ShowBadge, int BadgeCount, BottomNavigationMenuView _bottomNavigationMenuView)
{
var itemView = (BottomNavigationItemView)_bottomNavigationMenuView.GetChildAt(index);
if (ShowBadge && BadgeCount > 0)
{
var mtxtnotificationsbadge = itemView.FindViewById<TextView>(Resource.Id.txtbadge);
if (mtxtnotificationsbadge == null)
{
var vBadge = LayoutInflater.From(CrossCurrentActivity.Current.Activity).Inflate(Resource.Layout.notification_badge, _bottomNavigationMenuView, false);
itemView.AddView(vBadge);
mtxtnotificationsbadge = itemView.FindViewById<TextView>(Resource.Id.txtbadge);
}
mtxtnotificationsbadge.Text = BadgeCount.ToString();
if (mtxtnotificationsbadge.Text.Length == 1)
mtxtnotificationsbadge.SetBackgroundResource(Resource.Drawable.custom_circle_shape);
else
mtxtnotificationsbadge.SetBackgroundResource(Resource.Drawable.custom_rectangle_shape);
}
else
{
var badgeLayout = itemView.FindViewById<FrameLayout>(Resource.Id.badge);
if (badgeLayout != null)
itemView.RemoveView(badgeLayout);
}
}
}
}
then under resource/layout (notification_badge.axml):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="@+id/badge"
android:layout_height="match_parent">
<TextView
android:id="@+id/txtbadge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:gravity="center"
android:padding="3dp"
android:textColor="@color/white"
android:textSize="11sp" />
</FrameLayout>
custom_rectangle_shape.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#f00"/>
<corners
android:bottomRightRadius="60dp"
android:bottomLeftRadius="60dp"
android:topLeftRadius="60dp"
android:topRightRadius="60dp" />
</shape>
custom_circle_shape.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#f00"/>
<corners
android:bottomRightRadius="60dp"
android:bottomLeftRadius="60dp"
android:topLeftRadius="60dp"
android:topRightRadius="60dp" />
</shape>
iOS
[assembly: ExportRenderer(typeof(Shell), typeof(CustomShellRenderer))]
namespace Xamarin.iOS.Renderers
{
/// <summary>
/// The CustomShellRenderer is necessary in order to replace the ShellItemRenderer with your own.
/// </summary>
class CustomShellRenderer : ShellRenderer
{
public CustomShellRenderer() : base()
{ }
protected override IShellTabBarAppearanceTracker CreateTabBarAppearanceTracker()
{
return new CustomShellBottomAppearance();
}
}
}
And then the CustomShellBottomAppearance.cs:
namespace Xamarin.iOS.Renderers
{
public class CustomShellBottomAppearance : IShellTabBarAppearanceTracker
{
public void Dispose()
{ }
public void ResetAppearance(UITabBarController controller)
{ }
public async void SetAppearance(UITabBarController controller, ShellAppearance appearance)
{
if (controller?.TabBar?.Items != null && controller.TabBar.Items.Any())
{
var badge = await MainViewModel.CheckNewEventsAsync();
if (badge > 0)
controller.TabBar.Items[2].BadgeValue = badge.ToString();
}
}
public void UpdateLayout(UITabBarController controller)
{ }
}
}
result on iOS:
Thanks for the work around @galadril! Do you have the code for Resource.Drawable.custom_circle_shape and Resource.Drawable.custom_rectangle_shape?
Thanks for the work around @galadril! Do you have the code for Resource.Drawable.custom_circle_shape and Resource.Drawable.custom_rectangle_shape?
Ive added those drawable xml files to the comment as well.. sry
@galadril awesome!! many thanks!!
I imagine MainViewModel.CheckNewEventsAsync ()
checks for new notifications?
@galadril awesome!! many thanks!! I imagine
MainViewModel.CheckNewEventsAsync ()
checks for new notifications?
yeah thats the async method that gets the new event count, to show the badge
Any Updates or ETA on this?
In iOS you could set up a Subscription and call it from anywhere in your code. Building on @galadril example. In the renderer...
public async void SetAppearance(UITabBarController controller, ShellAppearance appearance) { if (controller?.TabBar?.Items != null && controller.TabBar.Items.Any()) {
MessagingCenter.Subscribe<Shell, string>(
this,
"BadgeTab1",
(shell, arg) =>
{
Device.BeginInvokeOnMainThread(() => controller.TabBar.Items[0].BadgeValue = arg);
});
MessagingCenter.Subscribe<Shell, string>(
this,
"BadgeTab2",
(shell, arg) =>
{
Device.BeginInvokeOnMainThread(() => controller.TabBar.Items[1].BadgeValue = arg);
});
}
}
Then you can call from inside your tab.
MessagingCenter.Send(Shell.Current, "BadgeTab2", "1");
I have another solution.
<Shell Shell.TabBarIsVisible="False">
Your layout
</Shell>
It will keep hiding all time without manually hide in other page.
<Grid x:Class="MyLib.Views.MyTab" BackgroundColor="#2196F3" ColumnSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
# Tabbar layout
<StackLayout Grid.Column="0" Padding="0,5,0,0" Orientation="Vertical">
<Image Source="course.png" WidthRequest="30" HeightRequest="30"></Image>
<Label Text="MyCourse" TextColor="White" HorizontalOptions="Center"></Label>
</StackLayout>
# Handle tapped, show badge, show selected mask
<AbsoluteLayout Grid.Column="0" x:Name="lay0">
<AbsoluteLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="OnSelected" CommandParameter="0"></TapGestureRecognizer>
</AbsoluteLayout.GestureRecognizers>
<Grid AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,1,1,1" IsVisible="true" BackgroundColor="White" Opacity="0.2"></Grid>
<Frame AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds=".9,0.1,12,12" CornerRadius="6" BackgroundColor="#cf1322" Padding="0"></Frame>
</AbsoluteLayout>
Other Tabs Here
</Grid>
TIPS: MyLib.Views.MyTab needs to inherit from Grid.
private void OnSelected(object sender, EventArgs e)
{
if (e is TappedEventArgs tap)
{
var newIndex = Convert.ToInt32(tap.Parameter);
var shell = Shell.Current;
shell.CurrentItem.CurrentItem = shell.CurrentItem.Items[newIndex];
}
}
int selectedIndex = -1;
public int SelectedIndex
{
get { return selectedIndex; }
set
{
if (selectedIndex != value)
{
selectedIndex = value;
switch (value)
{
case 0: this.lay0.Children[0].IsVisible = false; break;
case 1: this.lay1.Children[0].IsVisible = false; break;
case 2: this.lay2.Children[0].IsVisible = false; break;
case 3: this.lay3.Children[0].IsVisible = false; break;
}
}
}
}
<Grid Margin="0" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<local:MyTab Grid.Row="1" SelectedIndex="0"></local:MyTab>
Your original page layout here
</Grid>
Result on Android
@galadril Sorry, I have a question. How to reset BadgeCount value on android?
@galadril Thank you for your work on providing a workaround example for shell tabbar badges. Is there any chance you could please share the XAML referenced in CustomShellBottomAppearance.cs's SetAppearance method for the iOS platform?
@galadril How to reset BadgeCount value on android?
You can use MessagingCenter for this?
MessagingCenter.Send(this, App.MessageNameRemoveBadge);
Then in the SetAppearance :
MessagingCenter.Subscribe<MainPage>(this, App.MessageNameRemoveBadge, async app => await ClearBadgeAsync());
@galadril Thank you for your work on providing a workaround example for shell tabbar badges. Is there any chance you could please share the XAML referenced in CustomShellBottomAppearance.cs's SetAppearance method for the iOS platform?
There is not XAML reference in the iOS CustomShellBottomAppearance.cs's SetAppearance ...?
FYI as a workaround, I've managed to get the badges working on iOS and Android on tabs / shells via renderers. Maybe you can use some of this code for yourself..
Android
[assembly: ExportRenderer(typeof(Shell), typeof(CustomShellRenderer))] namespace Xamarin.Droid.Renderers { /// <summary> /// The CustomShellRenderer is necessary in order to replace the ShellItemRenderer with your own. /// </summary> class CustomShellRenderer : ShellRenderer { public CustomShellRenderer(Context context) : base(context) { } protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem) { return new CustomShellBottomAppearance(this); } } }
Then the CustomShellBottomAppearance.cs:
namespace Xamarin.Droid.Renderers { internal class CustomShellBottomAppearance : IShellBottomNavViewAppearanceTracker { public CustomShellBottomAppearance(CustomShellRenderer shellRenderer) { } public void Dispose() { } public void ResetAppearance(BottomNavigationView bottomView) { } public async void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance) { bottomView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilitySelected; var _bottomNavigationMenuView = (BottomNavigationMenuView)bottomView.GetChildAt(0); var badge = await MainViewModel.CheckNewEventsAsync(); CreatePageBadge(2, badge > 0, badge, _bottomNavigationMenuView); } private void CreatePageBadge(int index, bool ShowBadge, int BadgeCount, BottomNavigationMenuView _bottomNavigationMenuView) { var itemView = (BottomNavigationItemView)_bottomNavigationMenuView.GetChildAt(index); if (ShowBadge && BadgeCount > 0) { var mtxtnotificationsbadge = itemView.FindViewById<TextView>(Resource.Id.txtbadge); if (mtxtnotificationsbadge == null) { var vBadge = LayoutInflater.From(CrossCurrentActivity.Current.Activity).Inflate(Resource.Layout.notification_badge, _bottomNavigationMenuView, false); itemView.AddView(vBadge); mtxtnotificationsbadge = itemView.FindViewById<TextView>(Resource.Id.txtbadge); } mtxtnotificationsbadge.Text = BadgeCount.ToString(); if (mtxtnotificationsbadge.Text.Length == 1) mtxtnotificationsbadge.SetBackgroundResource(Resource.Drawable.custom_circle_shape); else mtxtnotificationsbadge.SetBackgroundResource(Resource.Drawable.custom_rectangle_shape); } else { var badgeLayout = itemView.FindViewById<FrameLayout>(Resource.Id.badge); if (badgeLayout != null) itemView.RemoveView(badgeLayout); } } } }
then under resource/layout (notification_badge.axml):
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:id="@+id/badge" android:layout_height="match_parent"> <TextView android:id="@+id/txtbadge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center_horizontal" android:layout_marginLeft="10dp" android:layout_marginStart="10dp" android:gravity="center" android:padding="3dp" android:textColor="@color/white" android:textSize="11sp" /> </FrameLayout>
custom_rectangle_shape.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#f00"/> <corners android:bottomRightRadius="60dp" android:bottomLeftRadius="60dp" android:topLeftRadius="60dp" android:topRightRadius="60dp" /> </shape>
custom_circle_shape.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#f00"/> <corners android:bottomRightRadius="60dp" android:bottomLeftRadius="60dp" android:topLeftRadius="60dp" android:topRightRadius="60dp" /> </shape>
iOS
[assembly: ExportRenderer(typeof(Shell), typeof(CustomShellRenderer))] namespace Xamarin.iOS.Renderers { /// <summary> /// The CustomShellRenderer is necessary in order to replace the ShellItemRenderer with your own. /// </summary> class CustomShellRenderer : ShellRenderer { public CustomShellRenderer() : base() { } protected override IShellTabBarAppearanceTracker CreateTabBarAppearanceTracker() { return new CustomShellBottomAppearance(); } } }
And then the CustomShellBottomAppearance.cs:
namespace Xamarin.iOS.Renderers { public class CustomShellBottomAppearance : IShellTabBarAppearanceTracker { public void Dispose() { } public void ResetAppearance(UITabBarController controller) { } public async void SetAppearance(UITabBarController controller, ShellAppearance appearance) { if (controller?.TabBar?.Items != null && controller.TabBar.Items.Any()) { var badge = await MainViewModel.CheckNewEventsAsync(); if (badge > 0) controller.TabBar.Items[2].BadgeValue = badge.ToString(); } } public void UpdateLayout(UITabBarController controller) { } } }
result on iOS:
Brother how can i set the badge in my class library main project? I have copied all this code..All my project backend code is in main library project..Now i want to set value of badge and show it on tab..How can i do this in mainpage.xaml file?
@galadril Thank you for your work on providing a workaround example for shell tabbar badges. Is there any chance you could please share the XAML referenced in CustomShellBottomAppearance.cs's SetAppearance method for the iOS platform?
There is not XAML reference in the iOS CustomShellBottomAppearance.cs's SetAppearance ...?
Very true @galadril there is no XAML referenced in your iOS platform's CustomShellBottomAppearance.cs's SetAppearance method but where we assign the badge value: "controller.TabBar.Items[2].BadgeValue = badge.ToString();". We are setting the value to a badge which I assume is either created on the client XAML side or in code for the iOS implementation of the Shell's tabbar. I am curious to see how you added the badges for iOS to the tabbar. Thank you in advance for your help.
At this moment I have a public static method that returns an int with the badge value:
var badge = await MainViewModel.CheckNewEventsAsync();
But you can easily use MessagingCenter for this, to subscribe for a new badge value.. Its up to you.
I have noticed that SetAppearance is called twice.
I for example, use a static variable and then in the notifications tab, I do my logic.
protected override async void OnNavigating(ShellNavigatingEventArgs args)
{
base.OnNavigating(args);
if (Current?.CurrentItem == null) return;
var s = args.Target.Location.ToString();
if (s.Contains("notificationsTab"))
{
//do something
}
}
@galadril Thank you for your work on providing a workaround example for shell tabbar badges. Is there any chance you could please share the XAML referenced in CustomShellBottomAppearance.cs's SetAppearance method for the iOS platform?
There is not XAML reference in the iOS CustomShellBottomAppearance.cs's SetAppearance ...?
Very true @galadril there is no XAML referenced in your iOS platform's CustomShellBottomAppearance.cs's SetAppearance method but where we assign the badge value: "controller.TabBar.Items[2].BadgeValue = badge.ToString();". We are setting the value to a badge which I assume is either created on the client XAML side or in code for the iOS implementation of the Shell's tabbar. I am curious to see how you added the badges for iOS to the tabbar. Thank you in advance for your help.
Hi @tawrey , I have the same question. Did you find how the XAML is?
At this moment I have a public static method that returns an int with the badge value:
var badge = await MainViewModel.CheckNewEventsAsync();
But you can easily use MessagingCenter for this, to subscribe for a new badge value.. Its up to you.
@galadril Do you have a repository in witch i can see your complete solution?
I would like to see how do you create your shell xaml.
Summary
There are requests for badge support for classic tabs and there are also some libraries out there which kinda support that. With shell it's not possible to use this libraries without touching / replacing too much of the shell internals so it would be great if shell supports this scenario out of the box. I couldn't find anything related in shell spec, that's why I'm proposing it here.
API Changes
Badges should be supported on all shell navigation patterns, which are
I propose the following properties for first iteration of badge support:
Primary properties
BaseShellItem (bindable properties)
BadgeText
: string to set the number (or something else) of notification-like itemsBadgeMoreText
: string to set the number (or something else) of the aggregated more tabBadgeTextColor
: Foreground color of badge textBadgeUnselectedTextColor
: Foreground color of badge text if underlying navigation item is in unselected stateBadgeEffectiveTextColor (readonly)
: IfBadgeUnselectedTextColor
is unset,BadgeTextColor
will be returned. Otherwise it will returnBadgeTextColor
if the underlying navigation item is in selected state orBadgeUnselectedTextColor
if in unselected state.BadgeColor
: background color of badgeBadgeUnselectedColor
: background color of badge if navigation item is in unselected stateBadgeEffectiveColor (readonly)
: IfBadgeUnselectedColor
is unset,BadgeColor
will be returned. Otherwise it will returnBadgeColor
if the underlying navigation item is in selected state orBadgeUnselectedColor
if in unselected state.Future implementations / considerations
Bottom tabs use the concept of the More tab if there are more than 5 items. All items with index >= 5 will be "hidden" by this more tab and handled by a platform specific context menu.
One use case would be the transformation of the underlying items hidden by this more tab. For example Item 5 (Messages) has "1" new item and Item 6 (Notifications) has "2" new items, so you could show "3" in the more tab, but the user would not how how this is split between the aggregated items.
We could think of modifying the text (e.g. for the example above "Messages (1)" and "Notifications (6)"). I'm proposing this because adding a badge to the underlying platform specific context menu could be too much work / impossible for a specific platform. Modifying the title value should definitely work though and we would see at least something.
Internal implementation
Android
Material components will support badges out of the box, which when I understood it correctly can be used when AndroidX is supported by Xamarin. In the meantime we have to supply a custom implementation like this for badges.
Flyout
Flyout menu is created by the
ShellFlyoutTemplatedContentRenderer
in combination withShellFlyoutRecyclerAdapter
. The data template is based on forms controls, so we just might use a Frame here for the default template. For custom templates the user has to provide the necessary controls and bind color, text, etc..Bottom tabs
ShellItemRenderer
usesBottomNavigationView
, which can be used to retrieve the underlyingBottomNavigationItemView
items and inject the badge view.The
more
tab uses aBottomSheetDialog
.Top tabs
ShellSectionRenderer
usesTabLayout
, which can be used to retrieve the underlayingTabView
items and inject the badge view.iOS
Flyout
Flyout menu is created by the
ShellTableViewController
in combination withShellTableViewSource
. The data template is based on forms controls, so we just might use a Frame here for the default template. For custom templates the user has to provide the necessary controls and bind color, text, etc..Bottom tabs
ShellItemRenderer
usesUITabBarController
which can use theUITabBarItem
to specify native Badge properties.The
more
tab uses the default implementation of theMoreNavigationController
ofUITabBarController
.Top tabs
ShellSectionRootRenderer
uses a UICollectionView, so you would have to modifyShellSectionHeaderCell
and add a custom badge view (something like this).Screenshots
TODO: Add them here
Feedback welcome.