From 1c70aa7654a50f2968a93db5de1536f746f17fb8 Mon Sep 17 00:00:00 2001 From: TamilarasanSF4853 Date: Thu, 25 Jun 2026 19:06:43 +0530 Subject: [PATCH] Revert "[iOS/MacCatalyst] Fix Entry clear button appearing dimmed compared to TextColor (#35541)" This reverts commit 180c367bcf3987ed78f67883cbc0f1db91a987e3. --- .../src/Platform/iOS/TextFieldExtensions.cs | 56 ++++++++++++++----- .../Handlers/Entry/EntryHandlerTests.iOS.cs | 40 +------------ 2 files changed, 45 insertions(+), 51 deletions(-) diff --git a/src/Core/src/Platform/iOS/TextFieldExtensions.cs b/src/Core/src/Platform/iOS/TextFieldExtensions.cs index cddc772a0eac..7d1040697be5 100644 --- a/src/Core/src/Platform/iOS/TextFieldExtensions.cs +++ b/src/Core/src/Platform/iOS/TextFieldExtensions.cs @@ -229,31 +229,61 @@ internal static void UpdateClearButtonColor(this UITextField textField, IEntry e { if (entry.TextColor is null) { - // Release any custom image so UIKit restores its own system clear button appearance. - // Setting TintColor to null alone is not enough — the template image persists. + // Setting TintColor to null allows the system to automatically apply the appropriate color based on the current theme (light or dark mode) + clearButton.TintColor = null; + // SetImage(null) releases the custom tinted bitmap so UIKit restores its system default. + // The color path (else branch) reads ImageForState(.Highlighted) to get that original + // image as the source for tinting. Without these calls, TintColor=null has no visual effect. clearButton.SetImage(null, UIControlState.Normal); clearButton.SetImage(null, UIControlState.Highlighted); - clearButton.TintColor = null; } else { - // Use AlwaysTemplate rendering so UIKit fills the icon at full opacity with TintColor, - // bypassing the semi-transparent pixels baked into the system clear button icon. - UIImage? sourceImage = clearButton.ImageForState(UIControlState.Normal) - ?? clearButton.ImageForState(UIControlState.Highlighted); + // On a null→color transition, UIKit restores the system image after SetImage(null), + // so ImageForState(Highlighted) returns the system clear button image as the tinting source. + UIImage? defaultClearImage = clearButton.ImageForState(UIControlState.Highlighted); + clearButton.TintColor = entry.TextColor.ToPlatform(); - if (sourceImage is not null) + var tintedClearImage = GetClearButtonTintImage(defaultClearImage, entry.TextColor.ToPlatform()); + if (tintedClearImage is not null) { - UIImage templateImage = sourceImage.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate); - clearButton.SetImage(templateImage, UIControlState.Normal); - clearButton.SetImage(templateImage, UIControlState.Highlighted); + clearButton.SetImage(tintedClearImage, UIControlState.Normal); + clearButton.SetImage(tintedClearImage, UIControlState.Highlighted); } - - clearButton.TintColor = entry.TextColor.ToPlatform(); } } } + internal static UIImage? GetClearButtonTintImage(UIImage? image, UIColor color) + { + if (image is null) + { + return null; + } + + var size = image.Size; + + var renderer = new UIGraphicsImageRenderer(size, new UIGraphicsImageRendererFormat() + { + Opaque = false, + Scale = UIScreen.MainScreen.Scale, + }); + + if (renderer is null) + { + return null; + } + + return renderer.CreateImage((context) => + { + image.Draw(CGPoint.Empty, CGBlendMode.Normal, 1.0f); + color.ColorWithAlpha(1.0f).SetFill(); + + var rect = new CGRect(CGPoint.Empty.X, CGPoint.Empty.Y, image.Size.Width, image.Size.Height); + context?.FillRect(rect, CGBlendMode.SourceIn); + }); + } + internal static void AddMauiDoneAccessoryView(this UITextField textField, IViewHandler handler) { #if !MACCATALYST diff --git a/src/Core/tests/DeviceTests/Handlers/Entry/EntryHandlerTests.iOS.cs b/src/Core/tests/DeviceTests/Handlers/Entry/EntryHandlerTests.iOS.cs index 446e796f09f1..1cb5c3f8895e 100644 --- a/src/Core/tests/DeviceTests/Handlers/Entry/EntryHandlerTests.iOS.cs +++ b/src/Core/tests/DeviceTests/Handlers/Entry/EntryHandlerTests.iOS.cs @@ -121,7 +121,7 @@ await AttachAndRun(entry, async (handler) => var tintedImage = clearButton.ImageForState(UIControlState.Normal); Assert.NotNull(tintedImage); - Assert.Equal(UIImageRenderingMode.AlwaysTemplate, tintedImage.RenderingMode); + Assert.Equal(UIImageRenderingMode.Automatic, tintedImage.RenderingMode); entry.TextColor = null; handler.UpdateValue(nameof(IEntry.TextColor)); @@ -139,7 +139,7 @@ await AttachAndRun(entry, async (handler) => // Confirms ImageForState(.Highlighted) returns the original after SetImage(null) var retintedImage = clearButton.ImageForState(UIControlState.Normal); Assert.NotNull(retintedImage); - Assert.Equal(UIImageRenderingMode.AlwaysTemplate, retintedImage.RenderingMode); + Assert.Equal(UIImageRenderingMode.Automatic, retintedImage.RenderingMode); }); } @@ -809,42 +809,6 @@ double GetNativeCharacterSpacing(EntryHandler entryHandler) return entry.AttributedText.GetCharacterSpacing(); } - [Fact(DisplayName = "Entry ClearButton uses template rendering tinted to TextColor")] - public async Task EntryClearButtonUsesTemplateRenderingTintedToTextColor() - { - var entry = new EntryStub - { - Text = "hello", - TextColor = Colors.Blue, - ClearButtonVisibility = ClearButtonVisibility.WhileEditing, - }; - - await InvokeOnMainThreadAsync(async () => - { - var handler = CreateHandler(entry); - var textField = GetNativeEntry(handler); - - await textField.AttachAndRun(async () => - { - textField.BecomeFirstResponder(); - - UIButton clearButton = null; - await AssertEventually(() => - { - clearButton = textField.ValueForKey(new NSString("clearButton")) as UIButton; - return clearButton?.ImageForState(UIControlState.Normal) is not null; - }, timeout: 2000); - - Assert.NotNull(clearButton); - Assert.Equal(Colors.Blue.ToPlatform(), clearButton.TintColor); - - var image = clearButton.ImageForState(UIControlState.Normal); - Assert.NotNull(image); - Assert.Equal(UIImageRenderingMode.AlwaysTemplate, image.RenderingMode); - }); - }); - } - static UITextField GetNativeEntry(EntryHandler entryHandler) => (UITextField)entryHandler.PlatformView;