0

I want to change the color of the active tab indictor dynamically. Multiple sources (Xamarin support, Xamarin docs) suggest there is a method that does just this, but it has to be done as a platform-specific for android

On<Android>().SetBarSelectedItemColor(color)

However, I'm testing this from the stock android template in Visual studio and it has no effect. It doesn't matter if I run it in the TabbedPage constructor, or as an event later.

Version info:

Xamarin Forms: 3.5.0.129452
Visual Studio: 15.9.7
Xamarin.Android SDK: 9.1.7.0

Do platform-specifics only work under certain conditions?

Code:
Other than a few color binding experiments, it is stock code.

MainPage.xaml.cs (Note: App.OnChange does get triggered and the code is executed as expected)

using System;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Xamarin.Forms.Xaml;

namespace App1.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MainPage : Xamarin.Forms.TabbedPage
    {     
        public MainPage()
        {
            InitializeComponent();

            App.OnChange((prop, value) =>
            {
                if (prop == App.ActiveColorKey)
                {
                    On<Xamarin.Forms.PlatformConfiguration.Android>().SetBarSelectedItemColor(Color.FromHex(value));
                    On<Xamarin.Forms.PlatformConfiguration.Android>().SetBarItemColor(Color.FromHex(value));
                }
            });
        } 
    }
}

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:views="clr-namespace:App1.Views"
            x:Class="App1.Views.MainPage" BarBackgroundColor="{DynamicResource TabColor}">

    <TabbedPage.BarTextColor>
        <OnPlatform x:TypeArguments="Color">
            <On Platform="Android" Value="Green" />
        </OnPlatform>
    </TabbedPage.BarTextColor>
    <TabbedPage.Children>
        <NavigationPage Title="Browse">
            <NavigationPage.Icon>
                <OnPlatform x:TypeArguments="FileImageSource">
                    <On Platform="iOS" Value="tab_feed.png"/>
                </OnPlatform>
            </NavigationPage.Icon>
            <x:Arguments>
                <views:ItemsPage />
            </x:Arguments>
        </NavigationPage>

        <NavigationPage Title="About dog" BarBackgroundColor="Red" BackgroundColor="Yellow">
            <NavigationPage.Icon>
                <OnPlatform x:TypeArguments="FileImageSource">
                    <On Platform="iOS" Value="tab_about.png"/>
                </OnPlatform>
            </NavigationPage.Icon>
            <x:Arguments>
                <views:AboutPage />
            </x:Arguments>
        </NavigationPage>
    </TabbedPage.Children>
</TabbedPage>
farlee2121
  • 2,959
  • 4
  • 29
  • 41
  • 1
    Yeah, this method just worked for Xamarin.Android. You can show some code about problem.And here is a similar discussion for reference.(https://stackoverflow.com/questions/51606756/how-do-i-change-bottom-tabs-background-color/51607012) – Junior Jiang Feb 18 '19 at 02:16
  • I added some code. I've been playing with this for quite a while. I've tried a custom renderer (though don't have one in the code for the given question). Supposedly I should be able to directly access the underlying TabLayout to set the color [(source)](https://stackoverflow.com/questions/30904138/how-to-change-the-new-tablayout-indicator-color-and-height), but the TabbedRenderer doesn't expose Control like other renderers. I also can't seem to find it in the view hierarchy as suggested [here](https://github.com/xamarin/Xamarin.Forms/issues/4058) – farlee2121 Feb 18 '19 at 19:28
  • You can use **DynamicResource** to `SetBarSelectedItemColor` dynamically.I will post the answer.Need to pay attention to the use of DynamicResource.https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/resource-dictionaries , https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/styles/xaml/dynamic – Junior Jiang Feb 19 '19 at 03:02
  • I have updated answer. – Junior Jiang Feb 21 '19 at 09:20

1 Answers1

2

From official document , you can set static color for BarSelectedItem as follow:

<TabbedPage ...
            xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
            android:TabbedPage.ToolbarPlacement="Bottom"
            android:TabbedPage.BarItemColor="Black"
            android:TabbedPage.BarSelectedItemColor="Red">
    ...
</TabbedPage>

Solution:

By using DynamicResource,it can set BarSelectedItemColor dynamically:

android:TabbedPage.BarSelectedItemColor="Red"

To this:

android:TabbedPage.BarSelectedItemColor="{DynamicResource BarSelectedItemColor}"

Complete sample code:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:TabbedPageDemo;assembly=TabbedPageDemo"
            x:Class="TabbedPageDemo.TabbedPageDemoPage"
            xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
            android:TabbedPage.ToolbarPlacement="Bottom"
            android:TabbedPage.BarItemColor="Black"
            android:TabbedPage.BarSelectedItemColor="{DynamicResource BarSelectedItemColor}">

  <TabbedPage.Resources>
    <ResourceDictionary>
            <Color x:Key="BlueColor">Blue</Color>
            <Color x:Key="YellowColor">Yellow</Color>
        </ResourceDictionary>
  </TabbedPage.Resources>
  ...
</TabbedPage>

Where you want to change color can be set in ContentPage as follow:

 Resources["BarSelectedItemColor"] = Resources["BlueColor"];
 ...
 Resources["BarSelectedItemColor"] = Resources["YellowColor"];

If you do not need use this renderer,you should comment its reference. My Forms answer code will work.

//[assembly: ExportRenderer(typeof(TabbedPage), typeof(TabRenderer))]

 You need to comment its reference. My Forms answer code will work.

And should remove this property in Xaml:

<TabbedPage.BarTextColor>
        <OnPlatform x:TypeArguments="Color">
            <On Platform="Android" Value="Green" />
        </OnPlatform>
</TabbedPage.BarTextColor>
Junior Jiang
  • 12,430
  • 1
  • 10
  • 30
  • No luck. Even when I just set it as a static resource, the selected tab indicator is unaffected. It stays the default white color. No errors are thrown either. – farlee2121 Feb 19 '19 at 14:18
  • My solution has a Tabbar.axml. I am able to set the activity color statically by changing that file. However, whether or not app:tabIndicatorColor is set, the color is not affected by bindings in the xaml – farlee2121 Feb 19 '19 at 15:05
  • If StaicResource can work then DynamicResource can do that.You can show some code about StaicResource . – Junior Jiang Feb 20 '19 at 01:34
  • The StaticResource does not work. I have to change the axml to affect the color. For my StaticResource code, all I did was try your example, but change DynamicResource to StaticResource. I also tried your first example that just sets `android:TabbedPage.BarSelectedItemColor="Red"`. None of those produce any effect in my app. – farlee2121 Feb 20 '19 at 03:03
  • The using of StaticResource has a different with DynamicResource .If possible ,you can post your demo project, I will Check it. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/resource-dictionaries – Junior Jiang Feb 20 '19 at 03:09
  • I know StaticResource is different than Dynamic. I was trying to communicate that I was reducing the scope of the problem and it still wasn't working. Only directly changing the tabbar.axml had any effect. Any use of BarSelectedItemColor made no difference, whether it was a one time color change or dynamic. – farlee2121 Feb 20 '19 at 15:34
  • Here is a link to the solution zip https://1drv.ms/u/s!AhKS6Dm8ag3eiJwhprhvS6S1Iuo3qQ Thanks for helping me out! – farlee2121 Feb 20 '19 at 15:47
  • 1
    I find problem where is.There is a **Renderers** folder under your **App1.Android** solution. `TabRenderer.cs` doesn't have valid code, but it is bound to the `TabbedPage` class. This affects the code display in Forms. You need to comment its reference. The code for my Forms answer can work.`//[assembly: ExportRenderer(typeof(TabbedPage), typeof(TabRenderer))]` – Junior Jiang Feb 21 '19 at 09:14
  • Something must be different about my setup. I removed the renderer and ran through the different bindings again. Still no effect from any of them. – farlee2121 Feb 21 '19 at 15:12
  • Important evidence: VisualStudio shows a warning in MainPage.xaml for android:TabbedPage.BarSelectedItemColor. It says "The attachable property 'BarSelectedItemColor' was not found in type TabbedPage. The only two properties VS does suggest are `IsSwipePagingEnabled` and `IsSmoothScrollEnabled`. Those properties do bind properly. I must be missing some kind of dependency. – farlee2121 Feb 21 '19 at 15:38
  • Here is a brief screen cap of the app. https://1drv.ms/v/s!AhKS6Dm8ag3eiJwkL4a8-UqE9Sxf9A – farlee2121 Feb 22 '19 at 05:14
  • From video, `BarSelectedItemColor` has been setted as Green.It is no problem.Just set by DynamicResource can dynamically changed. – Junior Jiang Feb 22 '19 at 05:40
  • The `BarTextColor` is green the `BarSelectedItemColor` is white. Either that, or I'm misunderstanding `BarSelectedItemColor` and it is still not changing, because the code behind this video has `android:TabbedPage.BarSelectedItemColor="{DynamicResource TabColor}"`. – farlee2121 Feb 22 '19 at 13:16
  • 1
    Okey, because `TabPage Xaml` has `TabbedPage.BarTextColor`,and you set it as `Green`.Just Removing this property.`DynamicResource` will work.I have updated answer.If you solved your problem.Remember to mark it.Thanks.^.^ – Junior Jiang Feb 25 '19 at 02:44
  • Interesting. Removing the BarTextColor binding did allow BarSelectedItemColor to bind as expected (though I did need to remove ActiveTabColor from the mainpage resources so it could bind to the App level resource). However, this only changes the text color of the active tab, the bar at the bottom of the tab is unaffected. I suppose this is by design, but I find it very unintuitve and the property is not well clarified in the docs. I still need to be able to change the underlying bar color, but you've solved the problem I technically asked. You deserve the points. – farlee2121 Feb 25 '19 at 14:48
  • Thanks for marking."need to be able to change the underlying bar color" Does it mean `BarBackgroundColor`? – Junior Jiang Feb 26 '19 at 02:25
  • No, I have BarBackgroundColor working. I'm talking about "the bar at the bottom of the tab." In the video it the white bar in the currently selected tab. Its color can be set statically in Tabbar.axml via app:tabIndicatorColor. Based on our explorations, I don't think there is a forms property for this and I have been unable to access the underlying android TabLayout element. – farlee2121 Feb 26 '19 at 14:12
  • Here is a discussion about dynamically setting that color when you can directly access the TabLayout https://stackoverflow.com/questions/30904138/how-to-change-the-new-tablayout-indicator-color-and-height?noredirect=1&lq=1 – farlee2121 Feb 26 '19 at 14:14