Skip to content

[net10.0] [iOS, Windows] Fix: Switch does not use the native default on color when OnColor is unset #29694

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

Merged
merged 7 commits into from
Jun 13, 2025
Merged
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 74 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue29693.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 29693, "The default native on color is not displayed when the Switch on color is not explicitly set", PlatformAffected.UWP)]
public class Issue29693 : ContentPage
{
public Issue29693()
{
var defaultOnSwitch = new Switch
{
IsToggled = true,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
};

var defaultOffSwitch = new Switch
{
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};

var switchControl1 = new Switch
{
IsToggled = true,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};

var switchControl2 = new Switch
{
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};

var button1 = new Button
{
Text = "Toggle Switch 3",
AutomationId = "button1",
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};

var button2 = new Button
{
Text = "Toggle Switch 4",
AutomationId = "button2",
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
};

button1.Clicked += (sender, e) =>
{
switchControl1.IsToggled = !switchControl1.IsToggled;
};

button2.Clicked += (sender, e) =>
{
switchControl2.IsToggled = !switchControl2.IsToggled;
};

var verticalStackLayout = new VerticalStackLayout()
{
Spacing = 20,
Padding = new Thickness(20),
};
verticalStackLayout.Add(defaultOnSwitch);
verticalStackLayout.Add(defaultOffSwitch);
verticalStackLayout.Add(switchControl1);
verticalStackLayout.Add(switchControl2);
verticalStackLayout.Add(button1);
verticalStackLayout.Add(button2);

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.
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,24 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue29693 : _IssuesUITest
{
public override string Issue => "The default native on color is not displayed when the Switch on color is not explicitly set";

public Issue29693(TestDevice device)
: base(device)
{ }

[Test]
[Category(UITestCategories.Switch)]
public void VerifySwitchDefaultColors()
{
App.WaitForElement("button1");
App.Tap("button1");
App.Tap("button2");
VerifyScreenshot();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending snapshots already available in the latest build. Could you commit the images?
Example:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending snapshots already available in the latest build. Could you commit the images? Example: image

@jsuarezruiz, I have committed the pending snapshots.

}
}
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.
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.
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.
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.
8 changes: 7 additions & 1 deletion src/Core/src/Platform/Android/SwitchExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,23 @@ public static void UpdateTrackColor(this ASwitch aSwitch, ISwitch view)
var trackColor = view.TrackColor;

if (trackColor is not null)
{
aSwitch.TrackDrawable?.SetColorFilter(trackColor, FilterMode.SrcAtop);
}
else
{
aSwitch.TrackDrawable?.ClearColorFilter();
}
}

public static void UpdateThumbColor(this ASwitch aSwitch, ISwitch view)
{
var thumbColor = view.ThumbColor;

if (thumbColor != null)
if (thumbColor is not null)
{
aSwitch.ThumbDrawable?.SetColorFilter(thumbColor, FilterMode.SrcAtop);
}
}

public static Drawable? GetDefaultSwitchTrackDrawable(this ASwitch aSwitch) =>
Expand Down
62 changes: 46 additions & 16 deletions src/Core/src/Platform/Windows/SwitchExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,76 @@ public static class SwitchExtensions
{
public static void UpdateIsToggled(this ToggleSwitch toggleSwitch, ISwitch view)
{
if (toggleSwitch != null)
if (toggleSwitch is not null)
{
toggleSwitch.IsOn = view?.IsOn ?? false;
}
}

static readonly string[] toggleSwitchOnKeys =
{
"ToggleSwitchFillOn",
"ToggleSwitchFillOnPointerOver",
"ToggleSwitchFillOnPressed",
"ToggleSwitchFillOnDisabled"
};

static readonly string[] toggleSwitchOffKeys =
{
"ToggleSwitchFillOff",
"ToggleSwitchFillOffPointerOver",
"ToggleSwitchFillOffPressed",
"ToggleSwitchFillOffDisabled"
};

public static void UpdateTrackColor(this ToggleSwitch toggleSwitch, ISwitch view)
{
if (toggleSwitch == null)
if (toggleSwitch is null)
{
return;
}

var trackColor = view.TrackColor?.ToPlatform() ?? new SolidColorBrush(Color.FromArgb(6, 0, 0, 0));
var trackColor = view.TrackColor?.ToPlatform();

if (trackColor is not null)
{
if (view.IsOn)
{
toggleSwitch.Resources.SetValueForAllKey(toggleSwitchOnKeys, trackColor);
}
else
{
toggleSwitch.Resources.SetValueForAllKey(toggleSwitchOffKeys, trackColor);
}
}
else
{
if (view.IsOn)
{
toggleSwitch.Resources.RemoveKeys(toggleSwitchOnKeys);
}
else
{
toggleSwitch.Resources.RemoveKeys(toggleSwitchOffKeys);
}
}

toggleSwitch.TryUpdateResource(
trackColor,
"ToggleSwitchFillOn",
"ToggleSwitchFillOnPointerOver",
"ToggleSwitchFillOnPressed",
"ToggleSwitchFillOnDisabled",
"ToggleSwitchFillOff",
"ToggleSwitchFillOffPointerOver",
"ToggleSwitchFillOffPressed",
"ToggleSwitchFillOffDisabled");
toggleSwitch.RefreshThemeResources();
}

public static void UpdateThumbColor(this ToggleSwitch toggleSwitch, ISwitch view)
{
if (toggleSwitch == null)
if (toggleSwitch is null)
{
return;
}

if (view.ThumbColor == null)
if (view.ThumbColor is null)
{
return;
}

if (view.ThumbColor != null)
if (view.ThumbColor is not null)
{
toggleSwitch.TryUpdateResource(
view.ThumbColor.ToPlatform(),
Expand Down
38 changes: 29 additions & 9 deletions src/Core/src/Platform/iOS/SwitchExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,46 @@ public static void UpdateIsOn(this UISwitch uiSwitch, ISwitch view)

public static void UpdateTrackColor(this UISwitch uiSwitch, ISwitch view)
{
if (view == null)
if (view is null)
{
return;
}

var uIView = GetTrackSubview(uiSwitch);

if (uIView is null)
{
return;
}

var trackColor = view.TrackColor?.ToPlatform();

if (view.TrackColor is not null)
if (view.IsOn)
{
uiSwitch.OnTintColor = view.TrackColor.ToPlatform();
uIView.BackgroundColor = uiSwitch.OnTintColor;
if (trackColor is not null)
{
uiSwitch.OnTintColor = trackColor;
uIView.BackgroundColor = trackColor;
}
else
{
uiSwitch.OnTintColor = null;
uIView.BackgroundColor = null;
}
}

else
{
// iOS 13+ uses the UIColor.SecondarySystemFill to support Light and Dark mode
// else, use the RGBA equivalent of UIColor.SecondarySystemFill in Light mode
uiSwitch.OnTintColor = OperatingSystem.IsIOSVersionAtLeast(13) ? UIColor.SecondarySystemFill : DefaultBackgroundColor;
uIView.BackgroundColor = uiSwitch.OnTintColor;
if (trackColor is not null)
{
uIView.BackgroundColor = trackColor;
}
else
{
// iOS 13+ uses the UIColor.SecondarySystemFill to support Light and Dark mode
// else, use the RGBA equivalent of UIColor.SecondarySystemFill in Light mode
var fallbackColor = OperatingSystem.IsIOSVersionAtLeast(13) ? UIColor.SecondarySystemFill : DefaultBackgroundColor;
uIView.BackgroundColor = fallbackColor;
}
}
}

Expand Down
Loading