18
votes

I have a Xamarin Forms application and I am currently working on code for an iOS. In my settings I have an option to change the application's theme (Dark and Light). This basically just changes the background colors and text colors of the pages. Now what I want to do is to be able to change the SelectedImageTintColor and BarTintColor of the TabBar as well as the the BarTintColor and TintColor of the NavigationBar. At the moment I have create a renderer for the tabbed page:

protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
   base.OnElementChanged(e);
   App.theme = (Theme)App.DB.GetIntSetting("ThemeColor");
   switch (App.theme)
   {
      case Theme.Dark:
      {
         TabBar.SelectedImageTintColor = UIColor.FromRGB(255, 165, 0);
         TabBar.BarTintColor = UIColor.Black;
         break;
      }
      case Theme.Light:
      {
         TabBar.SelectedImageTintColor = UIColor.FromRGB(60, 132, 60);
         TabBar.BarTintColor = UIColor.White;
         break;
      }
   }
}

Right now these colors would only take effect when you first start the application.

enter image description here

I researched this problem but could not find any answer from anyone on how to solve this problem.

I know there have been many changes to Xamarin so I would like to find out if there are any recent developments or new ways to tackle this problem. I am open to looking into any possible suggestions as part of the requirement for the application is to be able to change these colors.

Edits:

My Tabbed page was created like the following:

public partial class MainPage : TabbedPage
{
   public MainPage()
   {
      InitializeComponent();
      var phrasesPage = new NavigationPage(new PhrasesPage())
      {
         Title = "Play",
         Icon = "play1.png"
      };
      var settingsPage = new NavigationPage(new SettingsPage())
      {
         Title = "Settings",
         Icon = "settings.png"
      };
      // other declarations here

      Children.Add(phrasesPage);
      Children.Add(settingsPage);
      // and more
   }
}

For instance, if I choose Dark theme then the TabBar and NavigationBar background color would be black, the TabBar's selectedimage would be orange and the NavigationBar's text would be white. Likewise if I choose Light theme then the TabBar and NavigationBar background color would be white, the TabBar's selectedimage would be green and the NavigationBar's text would be black.

3
Are you using xaml or straight code for your Views?Dan Siegel
Explain what you want exactly ? want to change icon color or background color of tabbar .KKRocks
@KKRocks please check my edits. Thanksuser6742877
ok and what is the problem faced you here ?KKRocks
@KKRocks --> Right now these colors would only take effect when you first start the application. I want it to to change whenever I change the theme.user6742877

3 Answers

9
votes

I think the problem is that you are not listening for and handling the theme change. You are setting the colors in OnElementChanged which is not going to be called again when you change the theme.

You can create a property that will fire off an event that you subscribe to in your custom renderer. For example, if you create the property in your App class then in your custom TabbedPage renderer you can do:

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

    if(e.OldElement != null)
    {
        App.Current.PropertyChanged -= Current_PropertyChanged;
        return;
    }

    App.Current.PropertyChanged += Current_PropertyChanged; //subscribe to the App class' built in property changed event
    UpdateTheme();
}

void Current_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    if(e.PropertyName == "DarkTheme")
    {
        UpdateTheme();
    }
}

Since the navigation bar is controlled by the NavigationPage instead, you will have to listen for the property change there too. Fortunately you won't need a custom renderer since you can change the bar and text colors with Forms properties. So you can create a class that inherits from NavigationPage and subscribe to the event:

public class CustomNavigationPage : NavigationPage
{
    public CustomNavigationPage(Page root) : base(root)
    {
        if(Device.OS == TargetPlatform.iOS)
        {
            App.Current.PropertyChanged += Current_PropertyChanged;
        }
    }
}

I created a sample project that demonstrates all of this so you can check it out :)

1
votes

You can use tabbar's property to change background and icon color whenever you need to use.

 TabBar.TintColor = UIColor.White; // changer as per your need for tab icon's color
TabBar.BarTintColor = UIColor.Black; // changer as per your need for tabbar's backgroungcolor 

same as for navigation

this.NavigationController.NavigationBar.TintColor = UIColor.White;//change as per your need for tab icon color

this.NavigationController.NavigationBar.BarTintColor = UIColor.Black;// changer as per your need for Navbar' backgroungcolor 
0
votes

Do you know about "Dynamic Resource" feature in Xamarin Forms?

I will give my way of doing it.May not be easy but I think it can work.

Step 1: In app.xaml set keys and default icons as below

<FileImageSource x:Key="PlayIconKey">playdark.png</FileImageSource>
<FileImageSource x:Key="AboutIconKey">aboutdark.png</FileImageSource>

and

<Image Source="{ DynamicResource PlayIconKey }" />
<Image Source="{ DynamicResource AboutIconKey}" />

etc..

Step 2: In your tabbed page set like

var phrasesPage = new NavigationPage(new PhrasesPage())
{
 Title = "Play",
 Icon = Application.Current.Resources["PlayIconKey"]
};

and so on for other pages in TabbedPage

Step 3: Now when you change settings just set

Application.Current.Resources["PlayIconKey"] = "playlight.png" 

and other icons here.

With this approach you can change all icons in one place. Let me know your opinion on this.