diff --git a/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs b/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs index 4a2fcddbde35..4bdd0f9c930c 100644 --- a/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs @@ -188,6 +188,40 @@ await InvokeOnMainThreadAsync(() => Assert.Equal(requestedHeight, actualHeight); }); } + + [Theory(DisplayName = "SearchBar small HeightRequest keeps intrinsic minimum height on iOS/Mac")] + [InlineData(35)] + [InlineData(20)] + public async Task ValidateSearchBarSmallHeightRequestRendering(double requestedHeight) + { + // This test is gated to iOS/MacCatalyst 26+ where the handler clamp is applied + if (!OperatingSystem.IsIOSVersionAtLeast(26) && !OperatingSystem.IsMacCatalystVersionAtLeast(26)) + { + return; + } + + var searchBar = new SearchBar + { + HeightRequest = requestedHeight, + }; + + await InvokeOnMainThreadAsync(() => + { + var handler = CreateHandler(searchBar); + var platformControl = GetPlatformControl(handler); + + double actualHeight = 0; + double intrinsicHeight = 0; + + if (platformControl is UIKit.UISearchBar uiSearchBar) + { + actualHeight = uiSearchBar.Frame.Height; + intrinsicHeight = uiSearchBar.IntrinsicContentSize.Height; + } + + Assert.True(actualHeight >= intrinsicHeight, $"Expected SearchBar height to remain at least the intrinsic height ({intrinsicHeight}), but was {actualHeight} for HeightRequest={requestedHeight}."); + }); + } #endif } } diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySearchBarHeightRequestValues.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySearchBarHeightRequestValues.png new file mode 100644 index 000000000000..9759140348c2 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySearchBarHeightRequestValues.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue35286.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue35286.cs new file mode 100644 index 000000000000..ff0c195d5aff --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue35286.cs @@ -0,0 +1,47 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 35286, "Spacing problem with SearchBar", PlatformAffected.iOS | PlatformAffected.macOS)] +public class Issue35286 : ContentPage +{ + public Issue35286() + { + var content = new VerticalStackLayout + { + Padding = 10, + Spacing = 10, + Children = + { + new Label + { + Text = "SearchBar with HeightRequest=35", + AutomationId = "Issue35286Label1" + }, + // SearchBar with small HeightRequest - this should NOT have spacing issues + new SearchBar + { + Placeholder = "Search with HeightRequest=35", + HeightRequest = 35, + BackgroundColor = Colors.LightBlue, + AutomationId = "Issue35286SearchBar1" + }, + + new Label + { + Text = "SearchBar with HeightRequest=100", + AutomationId = "Issue35286Label2", + Margin = new Thickness(0, 20, 0, 0) + }, + // SearchBar with large HeightRequest - should work normally + new SearchBar + { + Placeholder = "Search with HeightRequest=100", + HeightRequest = 100, + BackgroundColor = Colors.LightBlue, + AutomationId = "Issue35286SearchBar2" + }, + } + }; + + Content = new ScrollView { Content = content }; + } +} diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySearchBarHeightRequestValues.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySearchBarHeightRequestValues.png new file mode 100644 index 000000000000..06b553735574 Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySearchBarHeightRequestValues.png differ diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35286.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35286.cs new file mode 100644 index 000000000000..ffc2026dd6bb --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35286.cs @@ -0,0 +1,20 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue35286 : _IssuesUITest +{ + public Issue35286(TestDevice device) : base(device) { } + + public override string Issue => "Spacing problem with SearchBar"; + + [Test] + [Category(UITestCategories.SearchBar)] + public void VerifySearchBarHeightRequestValues() + { + App.WaitForElement("Issue35286Label1"); + VerifyScreenshot(); + } +} diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySearchBarHeightRequestValues.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySearchBarHeightRequestValues.png new file mode 100644 index 000000000000..9de7aff39216 Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySearchBarHeightRequestValues.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifySearchBarHeightRequestValues.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifySearchBarHeightRequestValues.png new file mode 100644 index 000000000000..910d28bd0b2d Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifySearchBarHeightRequestValues.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifySearchBarPlaceholderAndBackgroundColor.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifySearchBarPlaceholderAndBackgroundColor.png index 1e8d006f6f17..19ba94b17f15 100644 Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifySearchBarPlaceholderAndBackgroundColor.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/VerifySearchBarPlaceholderAndBackgroundColor.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifySearchBarHeightRequestValues.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifySearchBarHeightRequestValues.png new file mode 100644 index 000000000000..f8592d4747aa Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifySearchBarHeightRequestValues.png differ diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cs index d304bc5aa273..a7a882041d0b 100644 --- a/src/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cs +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cs @@ -2,6 +2,7 @@ using Foundation; using Microsoft.Maui.Graphics; using UIKit; +using static Microsoft.Maui.Primitives.Dimension; namespace Microsoft.Maui.Handlers { @@ -42,8 +43,17 @@ public override Size GetDesiredSize(double widthConstraint, double heightConstra { PlatformView.SizeToFit(); + double intrinsicHeight = PlatformView.IntrinsicContentSize.Height; double constrainedWidth = ViewHandlerExtensions.ResolveConstraints(PlatformView.Frame.Width, VirtualView.Width, VirtualView.MinimumWidth, VirtualView.MaximumWidth); - double constrainedHeight = ViewHandlerExtensions.ResolveConstraints(PlatformView.Frame.Height, VirtualView.Height, VirtualView.MinimumHeight, VirtualView.MaximumHeight); + double constrainedHeight = ViewHandlerExtensions.ResolveConstraints(intrinsicHeight, VirtualView.Height, VirtualView.MinimumHeight, VirtualView.MaximumHeight); + + // On iOS/MacCatalyst 26, setting SearchBar height below its intrinsic size can shrink only the background + // while the internal UITextField keeps its native size (platform limitation). Clamp height to the intrinsic minimum. + if (OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26)) + { + constrainedHeight = Math.Max(constrainedHeight, intrinsicHeight); + } + return new Size(constrainedWidth, constrainedHeight); }