Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] [Android] Fix for the FontImageSource color is not applied properly to the Tab Icon #26757

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,6 @@ void UpdateIconAndStyle(ToolbarItem item)
{
Image = result?.Value;
Style = UIBarButtonItemStyle.Plain;
if (item.IconImageSource is FontImageSource fontImageSource && fontImageSource.Color is not null)
{
TintColor = fontImageSource.Color.ToPlatform();
}
});
}
}
Expand Down
113 changes: 53 additions & 60 deletions src/Controls/src/Core/Platform/Android/TabbedPageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ void TabSelected(TabLayout.Tab tab)
if (Element.Children.Count > selectedIndex && selectedIndex >= 0)
Element.CurrentPage = Element.Children[selectedIndex];

SetIconColorFilter(tab, true);
SetIconColorFilter(Element.CurrentPage, tab, true);
}

void TeardownPage(Page page)
Expand Down Expand Up @@ -525,10 +525,10 @@ void UpdateTabIcons()
}
}

protected virtual void SetTabIconImageSource(TabLayout.Tab tab, Drawable icon)
protected virtual void SetTabIconImageSource(Page page, TabLayout.Tab tab, Drawable icon)
{
tab.SetIcon(icon);
SetIconColorFilter(tab);
SetIconColorFilter(page, tab);
}

void SetTabIconImageSource(Page page, TabLayout.Tab tab)
Expand All @@ -537,7 +537,7 @@ void SetTabIconImageSource(Page page, TabLayout.Tab tab)
_context,
result =>
{
SetTabIconImageSource(tab, result?.Value);
SetTabIconImageSource(page, tab, result?.Value);
});
}

Expand Down Expand Up @@ -633,76 +633,69 @@ protected virtual ColorStateList GetItemTextColorStates()

protected virtual ColorStateList GetItemIconTintColorState()
{
if (IsBottomTabPlacement)
{
if (_orignalTabIconColors is null)
_orignalTabIconColors = _bottomNavigationView.ItemIconTintList;
}
// this ensures that existing behavior doesn't change
else if (!IsBottomTabPlacement && BarSelectedItemColor != null && BarItemColor == null)
return null;
if (_orignalTabIconColors is null)
_orignalTabIconColors = IsBottomTabPlacement ? _bottomNavigationView.ItemIconTintList : _tabLayout.TabIconTint;

Color barItemColor = BarItemColor;
Color barSelectedItemColor = BarSelectedItemColor;

if (barItemColor == null && barSelectedItemColor == null)
if (barItemColor is null && barSelectedItemColor is null)
return _orignalTabIconColors;

if (_newTabIconColors != null)
if (_newTabIconColors is not null)
return _newTabIconColors;

int defaultColor;
int defaultColor = 0;
int checkedColor;

if (barItemColor is not null)
{
defaultColor = barItemColor.ToPlatform().ToArgb();
}
else
{
defaultColor = GetDefaultColor(defaultColor);

if (barSelectedItemColor is not null)
checkedColor = barSelectedItemColor.ToPlatform().ToArgb();
else
checkedColor = GetDefaultColor(defaultColor);

_newTabIconColors = GetColorStateList(defaultColor, checkedColor);
return _newTabIconColors;
}

int GetDefaultColor(int defaultColor)
{
#pragma warning disable XAOBS001 // Obsolete
var styledAttributes =
TintTypedArray.ObtainStyledAttributes(_context.Context, null, Resource.Styleable.NavigationBarView, Resource.Attribute.bottomNavigationStyle, 0);
var styledAttributes =
TintTypedArray.ObtainStyledAttributes(_context.Context, null, Resource.Styleable.NavigationBarView, Resource.Attribute.bottomNavigationStyle, 0);
#pragma warning restore XAOBS001 // Obsolete

try
try
{
var defaultColors = styledAttributes.GetColorStateList(Resource.Styleable.NavigationBarView_itemIconTint);
if (defaultColors is not null)
{
var defaultColors = styledAttributes.GetColorStateList(Resource.Styleable.NavigationBarView_itemIconTint);
if (defaultColors is not null)
{
defaultColor = defaultColors.DefaultColor;
}
else
{
// These are the defaults currently set inside android
// It's very unlikely we'll hit this path because the
// NavigationBarView_itemIconTint should always resolve
// But just in case, we'll just hard code to some defaults
// instead of leaving the application in a broken state
if (IsDarkTheme)
defaultColor = new Color(1, 1, 1, 0.6f).ToPlatform();
else
defaultColor = new Color(0, 0, 0, 0.6f).ToPlatform();
}
defaultColor = defaultColors.DefaultColor;
}
finally
else
{
styledAttributes.Recycle();
// These are the defaults currently set inside android
// It's very unlikely we'll hit this path because the
// NavigationBarView_itemIconTint should always resolve
// But just in case, we'll just hard code to some defaults
// instead of leaving the application in a broken state
if (IsDarkTheme)
defaultColor = new Color(1, 1, 1, 0.6f).ToPlatform();
else
defaultColor = new Color(0, 0, 0, 0.6f).ToPlatform();
}
}

if (barItemColor == null && _orignalTabIconColors != null)
defaultColor = _orignalTabIconColors.DefaultColor;

int checkedColor = defaultColor;

if (barSelectedItemColor != null)
checkedColor = barSelectedItemColor.ToPlatform().ToArgb();

_newTabIconColors = GetColorStateList(defaultColor, checkedColor);
return _newTabIconColors;
finally
{
styledAttributes.Recycle();
}
return defaultColor;
}


void OnMoreSheetDismissed(object sender, EventArgs e)
{
var index = Element.Children.IndexOf(Element.CurrentPage);
Expand Down Expand Up @@ -737,11 +730,11 @@ void UpdateItemIconColor()
_bottomNavigationView.ItemIconTintList = GetItemIconTintColorState() ?? _orignalTabIconColors;
else
{
var colors = GetItemIconTintColorState() ?? _orignalTabIconColors;
for (int i = 0; i < _tabLayout.TabCount; i++)
{
TabLayout.Tab tab = _tabLayout.GetTabAt(i);
this.SetIconColorFilter(tab);
var page = Element.Children[i];
this.SetIconColorFilter(page, tab);
}
}
}
Expand Down Expand Up @@ -780,18 +773,18 @@ void UpdateBarTextColor()
_tabLayout.TabTextColors = _currentBarTextColorStateList;
}

void SetIconColorFilter(TabLayout.Tab tab)
void SetIconColorFilter(Page page, TabLayout.Tab tab)
{
SetIconColorFilter(tab, _tabLayout.GetTabAt(_tabLayout.SelectedTabPosition) == tab);
SetIconColorFilter(page, tab, _tabLayout.GetTabAt(_tabLayout.SelectedTabPosition) == tab);
}

void SetIconColorFilter(TabLayout.Tab tab, bool selected)
void SetIconColorFilter(Page page, TabLayout.Tab tab, bool selected)
{
var icon = tab.Icon;
if (icon == null)
return;

var colors = GetItemIconTintColorState();
ColorStateList colors = (page.IconImageSource is FontImageSource fontImageSource && fontImageSource.Color is not null) ? null : GetItemIconTintColorState();
if (colors == null)
ADrawableCompat.SetTintList(icon, null);
else
Expand Down Expand Up @@ -967,8 +960,8 @@ void TabLayout.IOnTabSelectedListener.OnTabSelected(TabLayout.Tab tab)

void TabLayout.IOnTabSelectedListener.OnTabUnselected(TabLayout.Tab tab)
{
_tabbedPageManager.SetIconColorFilter(tab, false);
_tabbedPageManager.SetIconColorFilter(_tabbedPageManager.Element.CurrentPage, tab, false);
}
}
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue26662.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
SelectedTabColor="Green"
UnselectedTabColor="gray"
xmlns:local="clr-namespace:Maui.Controls.Sample.Issues"
x:Class="Maui.Controls.Sample.Issues.Issue26662">

<local:Issue26662Tab1/>
<local:Issue26662Tab2/>
<local:Issue26662Tab3/>

</TabbedPage>
119 changes: 119 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue26662.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 26662, "Unable to dynamically set unselected IconImageSource Color on Android", PlatformAffected.All)]
public partial class Issue26662 : TabbedPage
{
public Issue26662()
{
InitializeComponent();
}

}

public class Issue26662Tab1 : ContentPage
{
public Issue26662Tab1()
{
//If no FontImageSource color is given, tab icon should be applied based on the SelectedTabColor and UnselectedTabColor.
IconImageSource = new FontImageSource
{
FontFamily = "Ion",
Glyph = "\uf30c",
Size = 15
};
Button button = new Button
{
Text = "Change Icon Color",
BackgroundColor = Colors.Blue,
TextColor = Colors.Red
};
button.AutomationId = "Button";
button.Clicked += (s, e) =>
{
//If the FontImageSource color is given, the tab icon color should be applied solely based on the specified color, regardless of the SelectedTabColor or UnselectedTabColor.
IconImageSource = new FontImageSource
{
FontFamily = "Ion",
Glyph = "\uf30c",
Color = Colors.Violet,
Size = 15
};

};
Title = "Tab 1";
var verticalStackLayout = new VerticalStackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = {
new Label
{
HorizontalOptions = LayoutOptions.Center,
Text = "Tab 1"
},
button
}

};
Content = verticalStackLayout;
}
}

public class Issue26662Tab2 : ContentPage
{
public Issue26662Tab2()
{
//The FontImageSource color is given. So, the tab icon color should be applied based solely on the given color, regardless of the selected tab or unselected tab color.
IconImageSource = new FontImageSource
{
FontFamily = "Ion",
Glyph = "\uf30c",
Color = Colors.DodgerBlue,
Size = 15
};

Title = "Tab 2";
var verticalStackLayout = new VerticalStackLayout
{
VerticalOptions = LayoutOptions.Center,
Children =
{
new Label
{
HorizontalOptions = LayoutOptions.Center,
Text = "Tab 2"
},
}
};
Content = verticalStackLayout;
}
}
public class Issue26662Tab3 : ContentPage
{
public Issue26662Tab3()
{
//The FontImageSource color is given. So, the icon color should be applied based solely on the given color, regardless of the selected tab or unselected tab color.
IconImageSource = new FontImageSource
{
FontFamily = "Ion",
Glyph = "\uf30c",
Color = Colors.Red,
Size = 15
};

Title = "Tab 3";
var verticalStackLayout = new VerticalStackLayout
{
VerticalOptions = LayoutOptions.Center,
Children =
{
new Label
{
HorizontalOptions = LayoutOptions.Center,
Text = "Tab 3"
},
}
};
Content = verticalStackLayout;
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// FontImageSource color is not applied to the Tab Icon on Windows for the Tabbedpage
// Issue: https://github.com/dotnet/maui/issues/26752
#if TEST_FAILS_ON_WINDOWS
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue26662 : _IssuesUITest
{
public Issue26662(TestDevice device) : base(device) { }

public override string Issue => "Unable to dynamically set unselected IconImageSource Color on Android";

[Test, Order(1)]
[Category(UITestCategories.ActivityIndicator)]
public void FontImageSourceColorShouldApplyOnTabIcon()
{
App.WaitForElement("Button");
VerifyScreenshot();
}

[Test, Order(2)]
[Category(UITestCategories.ActivityIndicator)]
public void DynamicFontImageSourceColorShouldApplyOnTabIcon()
{
App.WaitForElement("Button");
App.Tap("Button");
VerifyScreenshot();
}
}
}
#endif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/Core/src/ImageSources/iOS/ImageSourceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static partial class ImageSourceExtensions
var image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();

return image.ImageWithRenderingMode(UIImageRenderingMode.Automatic);
return image.ImageWithRenderingMode(imageSource.Color == null ? UIImageRenderingMode.Automatic : UIImageRenderingMode.AlwaysOriginal);
}

internal static UIImage? GetPlatformImage(this IFileImageSource imageSource)
Expand Down