I am creating a mobile app using Microsoft's MAUI framework. To toggle a particular feature on and off, I have put a Switch element in the TitleView of the NavigationPage I'm working on.
Because I used an Android theme with a dark-colored action bar, the track of the Switch fades into the background on that platform. I fixed this by using a Handler, which lets me set the TrackColor of the Switch on Android.
The catch: when I toggle the Switch, the colors snap back to the originals.
In the XAML file:
<NavigationPage.TitleView>
<StackLayout Orientation="Horizontal">
<Switch x:Name="mySwitch" IsVisible="True" OnColor="White" HorizontalOptions="End" Toggled="MySwitchToggled">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="On">
<VisualState.Setters>
<Setter Property="ThumbColor" Value="#0082FC" /> <!--switch handle bright blue when on-->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Off">
<VisualState.Setters>
<Setter Property="ThumbColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Switch>
</StackLayout>
</NavigationPage.TitleView>
In the codebehind file:
public ItemListPage(int areaId, string areaName)
{
InitializeComponent();
//some unrelated code removed here
ModifySwitchColors(); //fix switch colors on Android
}
private void ModifySwitchColors()
{
#if ANDROID
var bgColor = Microsoft.Maui.Graphics.Colors.Gray;
SwitchHandler.Mapper.AppendToMapping("CustomColors", (handler, view) => DependencyService.Get<INativeCalls>().ModifySwitchTrackColor(handler, view, bgColor));
#endif
}
In the implementation of the platform-specific code interface:
public void ModifySwitchTrackColor(ISwitchHandler handler, ISwitch view, Microsoft.Maui.Graphics.Color inColor)
{
inColor.ToRgba(out var rByte, out var gByte, out var bByte, out var aByte);
var color = new Android.Graphics.Color(rByte, gByte, bByte, aByte);
if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
{
handler.PlatformView.TrackDrawable.SetColorFilter(new Android.Graphics.BlendModeColorFilter(color, Android.Graphics.BlendMode.SrcAtop));
}
else
{
handler.PlatformView.TrackDrawable.SetColorFilter(color, Android.Graphics.PorterDuff.Mode.SrcAtop);
}
}
Is there a way I can fix this?
I finally solved it, but it took some digging. The solution was to edit the track tint list of the switch, instead of adding a color filter:
public void ModifySwitchTrackColor(ISwitchHandler handler)
{
//colors use argb format.
//16842912 is Android.r.attr.state_checked which isn't in the MAUI interfaces for some reason
handler.PlatformView.TrackTintList = new ColorStateList(
new int[][] {
new int[] { 16842912 },
new int[] { } //default
},
new int[] {
Android.Graphics.Color.ParseColor("#FFFFFFFF"), //checked
Android.Graphics.Color.ParseColor("#FFBBBBBB") //unchecked
}
);
}
Note that I had to directly specify the constant for the android.R.attr.state_checked
state - MAUI's files didn't have it. I don't know why this is.
Then, instead of calling this function using AppendToMapping, I called it directly after the Page loaded:
void PostOnAppearing(object sender, EventArgs e) //page Loaded event handler
{
DependencyService.Get<INativeCalls>().ModifySwitchTrackColor(mySwitch.Handler as ISwitchHandler);
}
After calling it once, it sticks for the rest of the page load. Hooray!