Open MAUIoxo opened 10 months ago
Hi @MAUIoxo. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md
This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
Could be related? https://github.com/dotnet/maui/issues/19882
I added an example project that shows this Bug: ThumbColorNotReset_19883
I don't think that #19882 is related. The Switch
is within a Grid
, but the other Bug is about Grid.Resources
that overwrite globally defined Styles (e.g. for Labels) completely when a property is defined as a Grid.Resource
(intention e.g. define a HorizontalOption
for all Labels within this Grid
) and this is not the same here
First of all, I fooled myself by not choosing a more distinct OnColor and did not see that also the OnColor is not set! The OnColor should be Orange, but is not assigned. Can also be seen in the same project I attached
Verified this on Visual Studio Enterprise 17.10.0 Preview 1(8.0.6). Repro on Android 14.0-API34 and iOS 17.2 with below Project: ThumbColorNotReset.zip
Related: https://github.com/dotnet/maui/issues/20278 https://github.com/dotnet/maui/issues/19380
It doesn't appear to be related to Grids. Even the most basic example fails 100% of the time:
<Switch ThumbColor="Red" OnColor="Green"/>
Do you guys not have any integration tests? Or use MAUI internally? This wouldn't have made it past even cursory testing.
That’s also one of my biggest blames that things that used to work „somehow“ got broken and obviously nobody detected it - just the „Clients“ (we). What does that tell us? 😉
@MAUIoxo this will probably be fixed in this PR https://github.com/dotnet/maui/pull/20346
As also described in #20346 I worked on a solution with a CustomSwitchHandler
for iOS which you find below. While doing that, I found out that I just have to use a trivial thing and it worked for me just simply by using a CustomSwitch
that derived from Switch
. By doing that, I could simply use this CustomSwitch
in my XAML
and then use the Color settings from OnColor
and ThumbColor
and it worked.
Here are both ways which were tested with <MauiVersion>8.0.40-nightly.10485</MauiVersion>
.
This is the implementation of the CustomSwitchHandler
for iOS:
CustomSwitch:
namespace OptimizerApp.Pages.Views.Controls.CustomSwitch
{
public class CustomSwitch : Switch
{
}
}
Integration in XAML Code:
...
<constrols:CustomSwitch ... IsToggled="{Binding IsSelected, Mode=TwoWay}" ThumbColor="{StaticResource Gray100}" OnColor="{StaticResource DarkOrange1}" />
...
CustomSwitchHandler:
#if IOS
using OptimizerApp.Pages.Views.Controls.CustomSwitch;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
using UIKit;
namespace OptimizerApp.Platforms.iOS.ControlHandlers
{
public partial class CustomSwitchHandler : ViewHandler<CustomSwitch, UISwitch>
{
/// <summary>
/// Configures property mappings for the CustomSwitch and binds UI properties to platform-specific handlers.
/// This mapper directs changes in MAUI's CustomSwitch properties to appropriate methods that
/// update the native iOS UISwitch, ensuring UI consistency and responsiveness:
/// - 'IsToggled' updates the switch's active state.
/// - 'OnColor' adjusts the color when the switch is on.
/// - 'ThumbColor' changes the color of the switch thumb.
/// These mappings ensure that the visual state of the UISwitch is synchronized with the CustomSwitch.
/// </summary>
public static PropertyMapper<CustomSwitch, CustomSwitchHandler> CustomSwitchMapper = new PropertyMapper<CustomSwitch, CustomSwitchHandler>
{
[nameof(CustomSwitch.IsToggled)] = MapIsToggled,
[nameof(CustomSwitch.OnColor)] = MapOnColor,
[nameof(CustomSwitch.ThumbColor)] = MapThumbColor
};
public CustomSwitchHandler() : base(CustomSwitchMapper)
{
}
/// <summary>
/// Creates the native UISwitch view
/// </summary>
/// <returns>The newly created UISwitch instance</returns>
protected override UISwitch CreatePlatformView()
{
return new UISwitch();
}
/// <summary>
/// Connects this handler to the UISwitch, setting up event handlers and initial state
/// </summary>
/// <param name="platformView">The UISwitch to connect</param>
protected override void ConnectHandler(UISwitch platformView)
{
base.ConnectHandler(platformView);
platformView.ValueChanged += OnSwitchValueChanged;
platformView.On = VirtualView.IsToggled; // Synchronize the UISwitch's state with the IsToggled property of the MAUI CustomSwitch
SetSwitchColors(platformView, VirtualView);
}
/// <summary>
/// Disconnects this handler from the UISwitch and clean up the event handlers
/// </summary>
/// <param name="platformView">The UISwitch to disconnect</param>
protected override void DisconnectHandler(UISwitch platformView)
{
platformView.ValueChanged -= OnSwitchValueChanged;
base.DisconnectHandler(platformView);
// Reset UI properties
ResetSwitchColors(platformView);
}
/// <summary>
/// Sets the ThumbColor and OnTintColor of the UISwitch based on the properties of the CustomSwitch
/// </summary>
/// <param name="uiSwitch">The native UISwitch</param>
/// <param name="customSwitch">The MAUI CustomSwitch</param>
private static void SetSwitchColors(UISwitch uiSwitch, CustomSwitch customSwitch)
{
// Setting the null-values will set it to default values
uiSwitch.ThumbTintColor = customSwitch.ThumbColor != default(Color) ? customSwitch.ThumbColor.ToPlatform() : null;
uiSwitch.OnTintColor = customSwitch.OnColor != default(Color) ? customSwitch.OnColor.ToPlatform() : null;
}
/// <summary>
/// Resets the ThumbColor and OnTintColor properties of the UISwitch to defaults
/// </summary>
/// <param name="uiSwitch">The UISwitch to reset</param>
private void ResetSwitchColors(UISwitch uiSwitch)
{
uiSwitch.ThumbTintColor = null;
uiSwitch.OnTintColor = null;
}
/// <summary>
/// Map changes in the OnColor property to the UISwitch
/// </summary>
public static void MapOnColor(CustomSwitchHandler handler, CustomSwitch customSwitch)
{
if (handler.PlatformView != null)
{
handler.PlatformView.OnTintColor = customSwitch.OnColor.ToPlatform();
}
}
/// <summary>
/// Map changes in the ThumbColor property to the UISwitch
/// </summary>
public static void MapThumbColor(CustomSwitchHandler handler, CustomSwitch customSwitch)
{
if (handler.PlatformView != null)
{
handler.PlatformView.ThumbTintColor = customSwitch.ThumbColor.ToPlatform();
}
}
/// <summary>
/// Map changes in the IsToggled property to the UISwitch
/// </summary>
public static void MapIsToggled(CustomSwitchHandler handler, CustomSwitch customSwitch)
{
if (handler.PlatformView != null)
{
handler.PlatformView.On = customSwitch.IsToggled;
handler.UpdateSwitchColors(handler.PlatformView, customSwitch); // Update colors when switch is toggled/untoggled
}
}
private void OnSwitchValueChanged(object sender, EventArgs e)
{
var uiSwitch = (UISwitch)sender;
VirtualView.IsToggled = uiSwitch.On;
UpdateSwitchColors(uiSwitch, VirtualView);
}
/// <summary>
/// Update the OnTintColor and ThumbColor with the colors defined in the customSwitch
/// </summary>
private void UpdateSwitchColors(UISwitch uiSwitch, CustomSwitch customSwitch)
{
if (uiSwitch.On)
{
if (customSwitch.OnColor != default(Color))
{
uiSwitch.OnTintColor = customSwitch.OnColor.ToPlatform();
}
}
if (customSwitch.ThumbColor != default(Color))
{
uiSwitch.ThumbTintColor = customSwitch.ThumbColor.ToPlatform();
}
}
}
}
#endif
MauiProgram.cs:
...
#if IOS
using OptimizerApp.Platforms.iOS.ControlHandlers;
#endif
...
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
...
.ConfigureMauiHandlers(handlers =>
{
// The handler will only be called if the target platform is iOS
#if IOS
handlers.AddHandler<CustomSwitch, CustomSwitchHandler>();
#endif
});
...
Result:
BUT:
As mentioned above, it even does not have to be this full blown implementation. As I found out, it was sufficient to just use the simple CustomSwitch
above which simply derives from Switch
and use this in XAML
with corresponding Color settings.
Here are the before and after versions on iOS and Android :
Simple Switch iOS:
CustomSwitch iOS:
Simple Switch Android:
CustomSwitch Android:
I have the same issue wit Android
Description
I have a Switch in a Grid within a DataTemplate of a CollectionView with my own ThumbColor defined like in the example below:
Initially the Switch looks like below:
First of all, when the Switch is toggled, it gets its defined wrong OnColor (should be Orange):
After that when it is toggled off again, the defined
ThumbColor="{StaticResource Gray100}"
is not set back and the Switch looks as follows:Steps to Reproduce
In the linked example Project from repository:
Hint: The View containing the Switch with the ThumbColor and OnColor is in ..\Pages\Views**BottomSheetContentView.xaml**
Link to public reproduction project repository
ThumbColorNotReset_19883
Version with bug
8.0.6-nightly.9863
Is this a regression from previous behavior?
No, this is something new
Last version that worked well
7.0.101
Affected platforms
iOS, Android
Affected platform versions
No response
Did you find any workaround?
By the time this issue was reported, I did not find a workaround.
On April 13th 2024, I found the simples way that solved it for me, by just using a
CustomSwitch
that derived fromSwitch
and use this in myXAML
which fixed it for me as you can see below.Relevant log output
No response