Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

How to set badge counter above the toolbaritem in Xamarin.Forms?

Hi,

I am creating an application in that I need to implement badge counter above the icon in toolbaritem. I am creating dependancy service for ios and android. I get reference of this url. https://www.xamboy.com/2018/03/08/adding-badge-to-toolbaritem-in-xamarin-forms/
Atter implement this I am getting perfect result in android but when I try to run it over ios device than able to use that. In that var rightButtonItems = vc?.ParentViewController?.NavigationItem?.RightBarButtonItems;
I got this always null so I am not able to use and set badge counter above the application.
I am using .net standard class library.
I get my same issue over here: https://xamarin.github.io/bugzilla-archives/22/22621/bug.html

Let I share my code.

Badge.xaml.cs

private void ToolbarItem_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new Notification());
}
private void ContentPage_Appearing(object sender, EventArgs e)
{
base.OnAppearing();
ViewModel.AppearingCommand?.Execute(null);
if (ToolbarItems.Count > 0)
DependencyService.Get().SetBadge(this, ToolbarItems.First(), "4", Color.Red, Color.White);
}

IToolbarItemBadgeService.cs(In shared project)

public interface IToolbarItemBadgeService
{
void SetBadge(Page page, ToolbarItem item, string value, Color backgroundColor, Color textColor);
}

ToolbarItemBadgeService.cs(In iOS project)

[assembly: Dependency(typeof(ToolbarItemBadgeService))]
namespace CustomerServiceApp.iOS
{
public class ToolbarItemBadgeService : IToolbarItemBadgeService
{
public void SetBadge(Page page, ToolbarItem item, string value, Color backgroundColor, Color textColor)
{
Device.BeginInvokeOnMainThread(() =>
{
var renderer = Platform.GetRenderer(page);
if (renderer == null)
{
renderer = Platform.CreateRenderer(page);
Platform.SetRenderer(page, renderer);
}
var vc = renderer.ViewController;
var rightButtonItems = vc?.ParentViewController?.NavigationItem?.RightBarButtonItems;//Here i get null in rightButtonItems
// If we can't find the button where it typically is check the child view controllers
// as this is where MasterDetailPages are kept
if (rightButtonItems == null && vc.ChildViewControllerForHomeIndicatorAutoHidden != null)//vc.ChildViewControllerForHomeIndicatorAutoHidden is also return null
foreach (var uiObject in vc.ChildViewControllerForHomeIndicatorAutoHidden)
{
string uiObjectType = uiObject.GetType().ToString();
if (uiObjectType.Contains("FormsNav"))
{
UIKit.UINavigationBar navobj = (UIKit.UINavigationBar)uiObject;

                        if (navobj.Items != null)
                            foreach (UIKit.UINavigationItem navitem in navobj.Items)
                            {
                                if (navitem.RightBarButtonItems != null)
                                {
                                    rightButtonItems = navitem.RightBarButtonItems;
                                    break;
                                }
                            }
                    }
                }
            var idx = page.ToolbarItems.IndexOf(item);
            if (rightButtonItems != null && rightButtonItems.Length > idx)
            {
                var barItem = rightButtonItems[idx];
                if (barItem != null)
                {
                    barItem.UpdateBadge(value, backgroundColor.ToUIColor(), textColor.ToUIColor());
                }
            }
        });
    }
}

}

Can anyone look into this and suggest me what should I have to do in that?

Answers

  • LucasZhangLucasZhang Member, Xamarin Team Xamurai

    You can use custom renderer

    using System.Diagnostics;
    using Cirrious.FluentLayouts.Touch;
    using Core.Pages.Base;
    using Core.Views;
    using iOS.Controls;
    using iOS.Renderers;
    using UIKit;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.iOS;
    
    [assembly: ExportRenderer(typeof(ApplicationContentPageBase), typeof(ApplicationContentPageBaseRenderer))]
    namespace iOS.Renderers
    {
        public class ApplicationContentPageBaseRenderer : PageRenderer
        {
            private bool _initialized;
    
            private ApplicationContentPageBase Page => (ApplicationContentPageBase) Element;
    
            public override void ViewDidLoad()
            {
                if (_initialized)
                    return;
    
                MessagingCenter.Subscribe<BadgeToolbarItem, int>(this, BadgeToolbarItem.BadgeValueChangedMessage,
                    UpdateBadgeValue);
                _initialized = true;
    
                base.ViewDidLoad();
            }
    
            public override void ViewWillDisappear(bool animated)
            {
                base.ViewWillDisappear(animated);
    
                MessagingCenter.Unsubscribe<BadgeToolbarItem, int>(this, BadgeToolbarItem.BadgeValueChangedMessage);
            }
    
            private void UpdateBadgeValue(BadgeToolbarItem sender, int newValue)
            {
                var navigationItem = NavigationController.TopViewController.NavigationItem;
    
                var itemIndex = Page.ToolbarItems.Count - Page.ToolbarItems.IndexOf(sender) - 1;
                var item = navigationItem.RightBarButtonItems[itemIndex];
    
                if (newValue < 1)
                {
                    item.CustomView?.Dispose();
                    item.CustomView = null;
                    return;
                }
    
                var badge = new UIBadgeLabel(newValue);
    
                var customItemView = new UIImageView(item.Image);
                customItemView.AddSubview(badge);
    
                customItemView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
                customItemView.AddConstraints(
                    badge.AtTopOf(customItemView),
                    badge.AtRightOf(customItemView));
    
                customItemView.UserInteractionEnabled = true;
                customItemView.AddGestureRecognizer(new UITapGestureRecognizer(() =>
                {
                    var parameter = sender.CommandParameter;
                    sender.Command.Execute(parameter);
                }));
    
                item.CustomView = customItemView;
            }
        }
    }
    

    For more details you can check https://byteloom.marek-mierzwa.com/mobile/2017/07/03/badge-icon-notification-in-xamarin-forms-toolbaritems-on-ios.html

  • developer007developer007 Member ✭✭

    @LucasZhang Actually I am using content page and it is same for all page. It is a default content page that I currently use. I also try with your given code and get back to you. If anything is missing there. But I have doubt that the value of notification badge is changed much time after a certain time but if I am using custom page renderer than it does not change every time. So I prefer that badge is called on every time appearing method.

  • JohnHardmanJohnHardman GBUniversity admin

    @LucasZhang said:
    You can use custom renderer

    Do you have equivalent code for Android and UWP?

  • LucasZhangLucasZhang Member, Xamarin Team Xamurai
  • JohnHardmanJohnHardman GBUniversity admin

    Different approach, and it seems that @AlexDunn hasn't added the UWP version yet either :-)

  • gaurang9011gaurang9011 Member ✭✭

    Sample Project:
    https://drive.google.com/file/d/1c-AfysNr3hnrnb2yplkuewUSMoCFv9-j/view?usp=sharing

    Badge counter is working with Content Page but when you are working with tabbed page, badge counter is not working.

    Please let me know if you have any solution.

  • shamineshamine Member ✭✭

    @developer007 Hi , where u able to solve it , I am facing the same issue with IOS on master page

Sign In or Register to comment.