Search code examples
xamarinxamarin.iosxamarin.formscustom-renderertabbedpage

CustomTabRenderer for Xamarin.ios


I have been using Xamarin for a few months now, and still run into some trouble now and then. I am using a custom renderer to change the look and feel of my tabs. It works perfectly fine when switching between different tabs. However, when I navigate to my tabbedPage using:

Children.Add(new UnitMapPage { Title = "Map", Icon = "map.png" });
CurrentPage = mapPage;

The page opens on the correct tab, but the text of the TabbarItem looks exactly like the unselected items. As soon as you tap on any tab, it changes to the correct styling. Here is my custom renderer.

class CustomTabRenderer : TabbedRenderer
{
    private UnitViewModel _unitViewModel;
    private TabbedPage _unitPage;

    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);

        if (e.NewElement != null) {
            var unitPage = (TabbedPage)e.NewElement;
            _unitPage = unitPage;
            _unitViewModel = (UnitViewModel)_unitPage.BindingContext;
            _unitViewModel.PropertyChanged += OnElementPropertyChanged;
        }

        // Set Text Font for unselected tab states
        UITextAttributes normalTextAttributes = new UITextAttributes();
        normalTextAttributes.Font = UIFont.SystemFontOfSize(10.0F, UIFontWeight.Regular); // unselected
        normalTextAttributes.TextColor = UIColor.White;

        UITabBarItem.Appearance.SetTitleTextAttributes(normalTextAttributes, UIControlState.Normal);
    }

    void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "AlertCount")
        {
            if (TabBar.Items != null)
            {
                foreach (var item in TabBar.Items)
                {
                    item.Image = item.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
                    if (item.Title == "History" && _unitViewModel != null)
                    {
                        if (_unitViewModel.AlertCount > 0)
                            item.BadgeValue = _unitViewModel.AlertCount.ToString();
                        else
                            item.BadgeValue = null;
                    }
                }
            }
        }
    }

    public override void ViewWillAppear(bool animated)
    {
        if (TabBar.Items != null)
        {
            foreach (var item in TabBar.Items)
            {
                item.Image = item.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
                if (item.Title == "History" && _unitViewModel != null)
                {
                    if (_unitViewModel.AlertCount > 0)
                        item.BadgeValue = _unitViewModel.AlertCount.ToString();
                    else
                        item.BadgeValue = null;
                }
            }
        }
        base.ViewWillAppear(animated);
    }

    public override UIViewController SelectedViewController
    {
        get
        {
            UITextAttributes selectedTextAttributes = new UITextAttributes();
            selectedTextAttributes.Font = UIFont.SystemFontOfSize(12.0F, UIFontWeight.Heavy); // SELECTED
            if (base.SelectedViewController != null)
            {
                base.SelectedViewController.TabBarItem.SetTitleTextAttributes(selectedTextAttributes, UIControlState.Normal);
            }
            return base.SelectedViewController;
        }
        set
        {
            base.SelectedViewController = value;

            foreach (UIViewController viewController in base.ViewControllers)
            {
                UITextAttributes normalTextAttributes = new UITextAttributes();
                normalTextAttributes.Font = UIFont.SystemFontOfSize(10.0F, UIFontWeight.Regular); // unselected
                normalTextAttributes.TextColor = UIColor.White;

                viewController.TabBarItem.SetTitleTextAttributes(normalTextAttributes, UIControlState.Normal);
            }
        }
    }
}

Solution

  • The problem seemed to have crept in when I upgraded the device I was testing on from ios9 to ios10 (Can't confirm this as I am not able to find a ios9 device on which I can test this).

    Reading through an answer on this post: How do I override the Xamarin Forms TabbedPage item fonts for iOS?, made me try various things in my own ViewWillAppear.

    The problem was solved by changing my code to set the selectedTextAttributes in my ViewWillAppear. Not sure if this is the best way to do it, but it did the trick!

     public override void ViewWillAppear(bool animated)
        {
            if (TabBar.Items != null)
            {
                foreach (var item in TabBar.Items)
                {
                    item.Image = item.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
                    if (item.Title == "History" && _unitViewModel != null)
                    {
                        if (_unitViewModel.AlertCount > 0)
                            item.BadgeValue = _unitViewModel.AlertCount.ToString();
                        else
                            item.BadgeValue = null;
                    }
    
                    if (item.Title.Equals(_unitPage.CurrentPage.Title))
                    {
                        UITextAttributes selectedTextAttributes = new UITextAttributes();
                        selectedTextAttributes.Font = UIFont.SystemFontOfSize(12.0F, UIFontWeight.Heavy); // SELECTED
                        if (base.SelectedViewController != null)
                        {
                            base.SelectedViewController.TabBarItem.SetTitleTextAttributes(selectedTextAttributes, UIControlState.Normal);
                        }
                    }
                }
            }
            base.ViewWillAppear(animated);
        }