Closed ysbakker closed 5 months ago
Verified this issue with Visual Studio 17.10.0 Preview 1. Can repro on Android platform with sample project. https://github.com/ysbakker/MauiAndroidKeyboardIssueReproduction
I found a workaround for the issue. The issue was introduced with the following change: https://github.com/dotnet/maui/commit/55ed1ea28148f1ae4642873be51fc2cd094a4ac9
There is now a method OnViewAttachedToWindow, this triggers UpdateReturnType and that overwriting the KeyListener. To fix this you can register your own ViewAttachedToWindow listener that sets the KeyListener.
I'm using 8.0.204 (The current latest that get loaded when updating to the latest version of VS). And I added the keyboardhandler in the ViewAttachedToWindow listener , with the debugger attached I can see the assignment is called. But nothing happens. So the workaround does not work or is broken by the newest version. As samsung has a big market share, makes releasing impossible. (Migration from Xamarin.Forms enforced but it's a nightmare! Half of my userinterfaces don't work anymore, (Yes I know VerticalStacklayout does not support CenterAndExpand but if that was the only issue...) mostly the content does not show or does not format right, for example CollectionView.EmptyView does not show it's content until I set a fixed height and all kinds of weird behaviour. I understand sometimes an old architecture must be digged but this is costing lot's of money and not even capable of ending with the same. As developers we must be able to rely on documentation but the whole framework is so buggy it's just try and error and pray it works. Beside this issue I have many others!, too much to report, it would take me days todo so)
I have combined temporary workaround proposed by @naaeef and some code from issue #17152 and commit https://github.com/dotnet/maui/commit/55ed1ea28148f1ae4642873be51fc2cd094a4ac9
I have used NumericKeyListener
from question here but I don't know much about how it works or if there is any difference with DigitsKeyListener
regarding to InputType.
Hopefully there will be permanent fix soon because writing decimal numbers is crucial for my app and can't downgrade due to other fix in Maui CommunityToolkit...
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NumericEntryHack", (handler, entry) =>
{
if (entry.Keyboard == Keyboard.Numeric)
{
handler.PlatformView.ViewAttachedToWindow += (object? sender, ViewAttachedToWindowEventArgs e) =>
{
handler.PlatformView.KeyListener = new NumericKeyListener(handler.PlatformView.InputType);
//handler.PlatformView.KeyListener = DigitsKeyListener.GetInstance("0123456789-,.");
handler.PlatformView.ImeOptions = entry.ReturnType.ToPlatform();
};
}
});
I can confirm this solution works, thanks David. I'm now able to set a text handler that replaces the '.' from the samsung numeric keyboard ignoring localization of the phone into a ',' when the localization requires so. I will share my handler code. At this might help others. You need to restore the cursor when altering the text. This is now working on samsung phones for entering numeric decimal values.
namespace ShowPrices.Custom
{
public sealed partial class CustomEntryHandler : EntryHandler
{
protected override AppCompatEditText CreatePlatformView()
{
var native = base.CreatePlatformView();
native.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
native.KeyListener = new NumericKeyListener(Android.Text.InputTypes.ClassNumber);
return native;
}
protected override void DisconnectHandler(AppCompatEditText platformView)
{
base.DisconnectHandler(platformView);
}
internal void HandleControlActions(CustomEntry entry)
{
if (PlatformView.InputType.HasFlag(Android.Text.InputTypes.ClassNumber))
{
PlatformView.ViewAttachedToWindow += (object? sender, Android.Views.View.ViewAttachedToWindowEventArgs e) =>
{
PlatformView.KeyListener = new NumericKeyListener(PlatformView.InputType);
PlatformView.ImeOptions = entry.ReturnType.ToPlatform();
};
}
PlatformView.SetTextSize(Android.Util.ComplexUnitType.Px, (float)entry.FontSize);
switch (entry.HorizontalTextAlignment)
{
case TextAlignment.Start:
PlatformView.Gravity = GravityFlags.Start;
break;
case TextAlignment.End:
PlatformView.Gravity = GravityFlags.End;
break;
case TextAlignment.Center:
PlatformView.Gravity = GravityFlags.Center;
break;
};
}
internal void HandleTextActions(CustomEntry entry)
{
// Samsung phones workaround
if (
(CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("nl") ||
CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("fr") ||
CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("de")) &&
PlatformView.Text != null)
{
var newString = PlatformView.Text.Replace(".", ",");
if (newString != PlatformView.Text)
{
int cursorPos = PlatformView.SelectionStart;
PlatformView.Text = newString;
PlatformView.SetSelection(cursorPos);
}
}
}
}
}
The parent code:
using Android.Views;
using AndroidX.AppCompat.Widget;
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
using System.Globalization;
using TextAlignment = Microsoft.Maui.TextAlignment;
namespace ShowPrices.Custom
{
public sealed partial class CustomEntryHandler : EntryHandler
{
private CustomEntry? _CustomEntry;
protected override AppCompatEditText CreatePlatformView()
{
var native = base.CreatePlatformView();
native.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
native.KeyListener = new NumericKeyListener(Android.Text.InputTypes.ClassNumber);
return native;
}
protected override void DisconnectHandler(AppCompatEditText platformView)
{
platformView.ViewAttachedToWindow -= ViewAttachedHandler;
base.DisconnectHandler(platformView);
}
internal void HandleControlActions(CustomEntry entry)
{
this._CustomEntry = entry;
if (PlatformView.InputType.HasFlag(Android.Text.InputTypes.ClassNumber))
{
PlatformView.ViewAttachedToWindow += ViewAttachedHandler;
}
PlatformView.SetTextSize(Android.Util.ComplexUnitType.Px, (float)entry.FontSize);
switch (entry.HorizontalTextAlignment)
{
case TextAlignment.Start:
PlatformView.Gravity = GravityFlags.Start;
break;
case TextAlignment.End:
PlatformView.Gravity = GravityFlags.End;
break;
case TextAlignment.Center:
PlatformView.Gravity = GravityFlags.Center;
break;
};
}
internal void ViewAttachedHandler(object? sender, Android.Views.View.ViewAttachedToWindowEventArgs e)
{
if (this._CustomEntry is CustomEntry entry)
{
PlatformView.KeyListener = new NumericKeyListener(PlatformView.InputType);
PlatformView.ImeOptions = entry.ReturnType.ToPlatform();
}
}
internal void HandleTextActions(CustomEntry entry)
{
// Samsung phones workaround
if (
(CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("nl") ||
CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("fr") ||
CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("de")) &&
PlatformView.Text != null)
{
var newString = PlatformView.Text.Replace(".", ",");
if (newString != PlatformView.Text)
{
int cursorPos = PlatformView.SelectionStart;
PlatformView.Text = newString;
PlatformView.SetSelection(cursorPos);
}
}
}
}
}
And the numeric keylistener
using Android.Text;
using Android.Text.Method;
namespace ShowPrices.Custom
{
class NumericKeyListener : NumberKeyListener
{
public override InputTypes InputType { get; }
protected override char[] GetAcceptedChars() => "0123456789-,.".ToCharArray();
public NumericKeyListener(InputTypes inputType)
{
InputType = inputType;
}
}
}
Description
Some context
Localization of numeric keyboards on Android can be pretty confusing, so we wrote a workaround (loosely based on this solution) that allows the user to both use a period and a comma as a decimal separator. We added some logic to always translate the separator to the expected one, and an Android handler which adds a key listener to the Entry view that allows the user to enter both a '.' and a ','.
Handler:
Android handler:
NumericKeyListener:
The problem
The key listener no longer works in MAUI 8.0.6. The handler is registered, and the key listener is also added to the view. The breakpoint is hit in the
NumericKeyListener
constructor. But it no longer gets used. This results in the user only being able to enter their localized decimal separator.I made a reproducible example here: https://github.com/ysbakker/MauiAndroidKeyboardIssueReproduction
You can test this by changing the SDK in the
global.json
to either8.0.100
(working) or8.0.201
(not working) and runningdotnet workload restore
if you do not have that MAUI version. A dialog should show up whenever you press a button, which doesn't happen on the latter SDK version.What could be causing this?
Steps to Reproduce
Link to public reproduction project repository
https://github.com/ysbakker/MauiAndroidKeyboardIssueReproduction
Version with bug
8.0.6 SR1
Is this a regression from previous behavior?
Yes, this used to work in .NET MAUI
Last version that worked well
8.0.3 GA
Affected platforms
Android
Affected platform versions
No response
Did you find any workaround?
No. But do let me know if you have a different solution for the numeric input.
Relevant log output
No response