Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions src/Core/src/Platform/iOS/TextFieldExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,26 +227,40 @@ internal static void UpdateClearButtonColor(this UITextField textField, IEntry e
{
if (textField.ValueForKey(new NSString("clearButton")) is UIButton clearButton)
{
UIImage defaultClearImage = clearButton.ImageForState(UIControlState.Highlighted);

if (entry.TextColor is null)
{
// 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);
}
else
{
// 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();

var tintedClearImage = GetClearButtonTintImage(defaultClearImage, entry.TextColor.ToPlatform());
clearButton.SetImage(tintedClearImage, UIControlState.Normal);
clearButton.SetImage(tintedClearImage, UIControlState.Highlighted);
if (tintedClearImage is not null)
{
clearButton.SetImage(tintedClearImage, UIControlState.Normal);
clearButton.SetImage(tintedClearImage, UIControlState.Highlighted);
}
}
}
}

internal static UIImage? GetClearButtonTintImage(UIImage image, UIColor color)
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()
Expand Down
53 changes: 53 additions & 0 deletions src/Core/tests/DeviceTests/Handlers/Entry/EntryHandlerTests.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,56 @@ public async Task CharacterSpacingInitializesCorrectly()
Assert.Equal(xplatCharacterSpacing, values.PlatformViewValue);
}

[Fact(DisplayName = "Clear button image resets when TextColor is null")]
public async Task ClearButtonImageResetsWhenTextColorIsNull()
{
EntryStub entry = new EntryStub
{
Text = "MAUI",
ClearButtonVisibility = ClearButtonVisibility.WhileEditing,
TextColor = null
};

await AttachAndRun(entry, async (handler) =>
{
await AssertEventually(() => handler.PlatformView.IsLoaded());
Assert.True(handler.PlatformView.BecomeFirstResponder());
await AssertEventually(() => handler.PlatformView.IsFirstResponder);

var clearButton = GetNativeClearButton(handler);
Assert.NotNull(clearButton);

var defaultImage = clearButton.ImageForState(UIControlState.Normal);
Assert.NotNull(defaultImage);
Assert.Equal(UIImageRenderingMode.AlwaysOriginal, defaultImage.RenderingMode);

entry.TextColor = Colors.Purple;
handler.UpdateValue(nameof(IEntry.TextColor));

var tintedImage = clearButton.ImageForState(UIControlState.Normal);
Assert.NotNull(tintedImage);
Assert.Equal(UIImageRenderingMode.Automatic, tintedImage.RenderingMode);

entry.TextColor = null;
handler.UpdateValue(nameof(IEntry.TextColor));

// UIKit restores the original AlwaysOriginal system image when SetImage(null) is called
// on this private clearButton — ImageForState(.Highlighted) must return non-null for re-tinting to work.
var resetImage = clearButton.ImageForState(UIControlState.Normal);
Assert.NotNull(resetImage);
Assert.Equal(UIImageRenderingMode.AlwaysOriginal, resetImage.RenderingMode);

entry.TextColor = Colors.Blue;
handler.UpdateValue(nameof(IEntry.TextColor));

// Verify re-tinting works after reset (null→color→null→color)
// Confirms ImageForState(.Highlighted) returns the original after SetImage(null)
var retintedImage = clearButton.ImageForState(UIControlState.Normal);
Assert.NotNull(retintedImage);
Assert.Equal(UIImageRenderingMode.Automatic, retintedImage.RenderingMode);
});
}

[Fact]
public async Task NextMovesToNextEntry()
{
Expand Down Expand Up @@ -832,6 +882,9 @@ bool GetNativeIsChatKeyboard(EntryHandler entryHandler)
bool GetNativeClearButtonVisibility(EntryHandler entryHandler) =>
GetNativeEntry(entryHandler).ClearButtonMode == UITextFieldViewMode.WhileEditing;

static UIButton GetNativeClearButton(EntryHandler entryHandler) =>
GetNativeEntry(entryHandler).ValueForKey(new NSString("clearButton")) as UIButton;

UITextAlignment GetNativeHorizontalTextAlignment(EntryHandler entryHandler) =>
GetNativeEntry(entryHandler).TextAlignment;

Expand Down
Loading