bcl
bcl

Reputation: 518

Setting the font on navigation bar buttons in a Xamarin Forms iOS 13+ app

I'm trying to set the font for navigation buttons (specifically the Back button) in Xamarin iOS (13+) apps. I found this this solution which claims to work but didn't, for me at least:

var style = new UINavigationBarAppearance();

var a = new UIStringAttributes();
a.Font = UIFont.SystemFontOfSize(35);
a.ForegroundColor = UIColor.Yellow;
style.TitleTextAttributes = a;

var dic = new NSDictionary<NSString, NSObject>(
            new NSString[] {a.Dictionary.Keys[0] as NSString, a.Dictionary.Keys[1] as NSString }, a.Dictionary.Values
);
   
var button = new UIBarButtonItemAppearance(UIBarButtonItemStyle.Plain);
button.Normal.TitleTextAttributes = dic;
button.Highlighted.TitleTextAttributes = dic;
style.ButtonAppearance = button;

UINavigationBar.Appearance.StandardAppearance = style;

I then simplified it a little (seeing if I could simply recolour the nav bar title) but this again did nothing:

var style = new UINavigationBarAppearance();

var a = new UIStringAttributes()
{
    ForegroundColor = UIColor.Yellow
};
style.TitleTextAttributes = a;

UINavigationBar.Appearance.StandardAppearance = style;

Playing around further I found, curiously, the following DOES recolour the navigation bar title:

var a = new UIStringAttributes()
{
    ForegroundColor = UIColor.Yellow
};

UINavigationBar.Appearance.TitleTextAttributes = a;

...but using the same thought process, this does NOT recolour the navigation bar buttons:

var a = new UITextAttributes()
{
    TextColor = UIColor.Yellow
};

UIBarButtonItem.Appearance.SetTitleTextAttributes(a, UIControlState.Normal);

Can anyone see why none of these approaches work for modifying the navigation bar button styling? Or might this be an issue with Xamarin?

UPDATE: I realised the first sample does work, but only in Xamarin iOS. It does not work in Xamarin Forms however. It looks like Xamarin Forms might be enforcing its own standard appearance which overrides what I put in my code.

Upvotes: 0

Views: 452

Answers (2)

bcl
bcl

Reputation: 518

I finally figured out an approach that works by overriding Xamarin Forms' constant enforcement of its own navigation bar styling:

public class MyNavigationRenderer : NavigationRenderer
{
    public override void ViewDidAppear(bool animated)
    {
        base.ViewDidAppear(animated);

        UpdateStyle();

        Element.PropertyChanged += HandlePropertyChanged;
    }

    void UpdateStyle()
    {
        var navigationBarAppearance = NavigationBar.StandardAppearance;
        var titleTextAttributes = new UIStringAttributes
        {
            ForegroundColor = UIColor.Yellow,
            Font = UIFont.SystemFontOfSize(35)
        };

        var dic = new NSDictionary<NSString, NSObject>(
            new NSString[] { titleTextAttributes.Dictionary.Keys[0] as NSString, titleTextAttributes.Dictionary.Keys[1] as NSString }, titleTextAttributes.Dictionary.Values
        );

        var button = new UIBarButtonItemAppearance(UIBarButtonItemStyle.Plain);
        button.Normal.TitleTextAttributes = dic;
        button.Highlighted.TitleTextAttributes = dic;

        navigationBarAppearance.ButtonAppearance = button;

        NavigationBar.StandardAppearance = navigationBarAppearance;
        NavigationBar.CompactAppearance = navigationBarAppearance;
        NavigationBar.ScrollEdgeAppearance = navigationBarAppearance;
    }

    void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        UpdateStyle();
    }
}

Upvotes: 1

Lucas Zhang
Lucas Zhang

Reputation: 18861

In your case we could set a custom NavigationBar .

In your ViewController

If you want to let it works on all Controllers , you could define a base ViewController

 public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);
        var page = Element as ContentPage;
        NavigationController.NavigationBar.Hidden = true;
        double height = IsiphoneX();
        UIView backView = new UIView()
        {
            BackgroundColor = UIColor.White,
            Frame = new CGRect(0,20,UIScreen.MainScreen.Bounds.Width, height),
        };
        UIButton backBtn = new UIButton() {
            Frame = new CGRect(20, height-44, 40, 44),
            Font = UIFont.SystemFontOfSize(18),  // set style here
        } ;
        backBtn.SetTitle("Back", UIControlState.Normal);
        backBtn.SetTitleColor(UIColor.Blue, UIControlState.Normal);
        backBtn.AddTarget(this,new Selector("GoBack"),UIControlEvent.TouchUpInside);
        UILabel titleLabel = new UILabel() {
            Frame=new CGRect(UIScreen.MainScreen.Bounds.Width/2-75, 0,150, height),
            Font = UIFont.SystemFontOfSize(20),
            Text = page.Title,
            TextColor = UIColor.Black,
            Lines = 0,
        };
        UILabel line = new UILabel() {
            Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
            BackgroundColor = UIColor.Black,
        };

        backView.AddSubview(backBtn);
        backView.AddSubview(titleLabel);
        backView.AddSubview(line);
        View.AddSubview(backView);
    }
     double IsiphoneX()
    {
        double height = 44; //set height as you want here !!!
        if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
        {
            if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
            {
                height = 64;  //set height as you want here !!!
            }
        }
        return height;
    }
    [Export("GoBack")]
    void GoBack()
    {
        NavigationController.PopViewController(true);
    }
    public override void ViewWillDisappear(bool animated)
    {
        base.ViewWillDisappear(animated);

        NavigationController.NavigationBar.Hidden = false;
    }

In this way you could set all style as you want like BackgroundColor , TextColor or even set the back button as an image .

Upvotes: 1

Related Questions