diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySwitchControlSize.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySwitchControlSize.png new file mode 100644 index 000000000000..a2590e3fe88d Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySwitchControlSize.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28901.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28901.cs new file mode 100644 index 000000000000..903ce3291cf3 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28901.cs @@ -0,0 +1,49 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 28901, "[Windows] Switch control is not sizing properly", PlatformAffected.UWP)] +public class Issue28901 : ContentPage +{ + public Issue28901() + { + var switchControl = new Switch + { + IsToggled = true, + HorizontalOptions = LayoutOptions.End, + AutomationId = "SwitchControl" + }; + + var switchControl2 = new Switch(); + + var label = new Label + { + Text = "Switch Control", + VerticalOptions = LayoutOptions.Center, + }; + + var settingsLabel = new Label + { + Text = "Change View", + VerticalOptions = LayoutOptions.Center, + }; + + var horizontalStackLayout = new HorizontalStackLayout + { + Children = + { + label, + switchControl2, + settingsLabel + }, + }; + + Content = new VerticalStackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = + { + switchControl, + horizontalStackLayout, + } + }; + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySwitchControlSize.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySwitchControlSize.png new file mode 100644 index 000000000000..e05cd2a2d1a0 Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySwitchControlSize.png differ diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28901.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28901.cs new file mode 100644 index 000000000000..5581b0603d7e --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28901.cs @@ -0,0 +1,22 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue28901 : _IssuesUITest +{ + public override string Issue => "[Windows] Switch control is not sizing properly"; + + public Issue28901(TestDevice device) + : base(device) + { } + + [Test] + [Category(UITestCategories.Switch)] + public void VerifySwitchControlSize() + { + App.WaitForElement("SwitchControl"); + VerifyScreenshot(); + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_Click_VerifyVisualState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_Click_VerifyVisualState.png index cab25280763a..1610de6c8d64 100644 Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_Click_VerifyVisualState.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_Click_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_InitialState_VerifyVisualState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_InitialState_VerifyVisualState.png index a47e07be6c73..dc09bb1b554e 100644 Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_InitialState_VerifyVisualState.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_InitialState_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetFlowDirectionAndToggled_VerifyVisualState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetFlowDirectionAndToggled_VerifyVisualState.png index 95154fa648e3..e44e95895d90 100644 Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetFlowDirectionAndToggled_VerifyVisualState.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetFlowDirectionAndToggled_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetOnColorAndThumbColor_VerifyVisualState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetOnColorAndThumbColor_VerifyVisualState.png index 8df8384133a5..576ae78bfa5c 100644 Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetOnColorAndThumbColor_VerifyVisualState.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetOnColorAndThumbColor_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetThumbColorAndOnColor_VerifyVisualState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetThumbColorAndOnColor_VerifyVisualState.png index 8d5afb63d105..5e15168f440b 100644 Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetThumbColorAndOnColor_VerifyVisualState.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Switch_SetThumbColorAndOnColor_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/UpdatedIsEnabledProperty.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/UpdatedIsEnabledProperty.png index e110b6ac4a78..2339e90360ad 100644 Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/UpdatedIsEnabledProperty.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/UpdatedIsEnabledProperty.png differ diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySwitchControlSize.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySwitchControlSize.png new file mode 100644 index 000000000000..f52878304394 Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySwitchControlSize.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifySwitchControlSize.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifySwitchControlSize.png new file mode 100644 index 000000000000..56b75e2e5c3b Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifySwitchControlSize.png differ diff --git a/src/Core/src/Handlers/Switch/SwitchHandler.Windows.cs b/src/Core/src/Handlers/Switch/SwitchHandler.Windows.cs index e3629e73d365..2f6f27249dc5 100644 --- a/src/Core/src/Handlers/Switch/SwitchHandler.Windows.cs +++ b/src/Core/src/Handlers/Switch/SwitchHandler.Windows.cs @@ -15,31 +15,71 @@ public static void MapIsOn(ISwitchHandler handler, ISwitch view) public static void MapTrackColor(ISwitchHandler handler, ISwitch view) { if (handler is SwitchHandler) + { handler.PlatformView?.UpdateTrackColor(view); + } } public static void MapThumbColor(ISwitchHandler handler, ISwitch view) { if (handler is SwitchHandler) + { handler.PlatformView?.UpdateThumbColor(view); + } } protected override void DisconnectHandler(ToggleSwitch platformView) { base.DisconnectHandler(platformView); platformView.Toggled -= OnToggled; + platformView.Loaded -= OnLoaded; } protected override void ConnectHandler(ToggleSwitch platformView) { base.ConnectHandler(platformView); platformView.Toggled += OnToggled; + platformView.Loaded += OnLoaded; + } + + void OnLoaded(object sender, UI.Xaml.RoutedEventArgs e) + { + var toggleSwitch = (ToggleSwitch)sender; + + if (toggleSwitch is null) + { + return; + } + + var rootGrid = toggleSwitch.GetDescendantByName("SwitchAreaGrid")?.Parent as Grid; + if (rootGrid is not null && rootGrid.ColumnDefinitions.Count > 0) + { + // In the default ToggleSwitch template, the second column (index 1) is only used for spacing + // between the toggle knob and the On/Off content area (which is defined in the third column). + // Since MAUI does not support OnContent/OffContent, this spacing is unnecessary + // so we set its width to 0 to reduce unwanted layout padding. + rootGrid.ColumnDefinitions[1].Width = new UI.Xaml.GridLength(0); + } + } + + // TODO: Make it public in .NET 10.0 + internal static void MapSwitchMinimumWidth(IViewHandler handler, IView view) + { + // Update the native ToggleSwitch MinWidth to reflect the MAUI view's MinimumWidth, + // overriding the default WinUI MinWidth (154) since we're not supporting OnContent and OffContent. + // This ensures the control does not reserve unnecessary space for labels. + if (view is ISwitch switchView && handler is SwitchHandler switchHandler) + { + switchHandler.PlatformView?.UpdateMinWidth(switchView); + } } void OnToggled(object sender, UI.Xaml.RoutedEventArgs e) { if (VirtualView is null || PlatformView is null || VirtualView.IsOn == PlatformView.IsOn) + { return; + } VirtualView.IsOn = PlatformView.IsOn; } diff --git a/src/Core/src/Handlers/Switch/SwitchHandler.cs b/src/Core/src/Handlers/Switch/SwitchHandler.cs index 7fa2160b57af..0d5db177f8f2 100644 --- a/src/Core/src/Handlers/Switch/SwitchHandler.cs +++ b/src/Core/src/Handlers/Switch/SwitchHandler.cs @@ -20,6 +20,9 @@ public partial class SwitchHandler : ISwitchHandler [nameof(ISwitch.IsOn)] = MapIsOn, [nameof(ISwitch.ThumbColor)] = MapThumbColor, [nameof(ISwitch.TrackColor)] = MapTrackColor, +#if WINDOWS + [nameof(IView.MinimumWidth)] = MapSwitchMinimumWidth, +#endif }; public static CommandMapper CommandMapper = new(ViewCommandMapper) diff --git a/src/Core/src/Platform/Windows/SwitchExtensions.cs b/src/Core/src/Platform/Windows/SwitchExtensions.cs index ca36152c1c06..8f25c1525c1f 100644 --- a/src/Core/src/Platform/Windows/SwitchExtensions.cs +++ b/src/Core/src/Platform/Windows/SwitchExtensions.cs @@ -91,5 +91,18 @@ public static void UpdateThumbColor(this ToggleSwitch toggleSwitch, ISwitch view "ToggleSwitchKnobFillOffDisabled"); } } + + internal static void UpdateMinWidth(this ToggleSwitch toggleSwitch, ISwitch view) + { + double minWidth = view.MinimumWidth; + if (double.IsNaN(minWidth)) + { + toggleSwitch.MinWidth = 0; + } + else + { + toggleSwitch.MinWidth = minWidth; + } + } } } \ No newline at end of file