Search code examples
c#ios.netmaui

.NET MAUI: entry hidden behind keyboard on iOS


I am trying to get a .NET Maui app up and running and it is working quite well so far - with one major problem: I cannot get it fixed that an Entry/Editor control stays above the keyboard and doesn't get overlapped.

I know there is an open issue and it is in the backlog, but the app seems unusable until this is fixed. There have been a couple of workarounds like

[GitHub] dotnet/maui issue 4792,
[GitHub] dotnet/maui issue 10662 (#1) and
[GitHub] dotnet/maui issue 10662 (#2)

but I cannot get them to work when registering as a handler. #1 doesn't do anything and #2 crashes when loading any view.

There is a solution on StackOverflow as well (Question 72536074) - unfortunately this method ignores the keyboard height.

To reproduce the problem the simplest code example would be any ContentPage with the following content:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="EntryIssueMaui.MainPage">
    <ScrollView>
        <Entry VerticalOptions="End" BackgroundColor="LightCoral" /> 
    </ScrollView>
</ContentPage>

based on the default Maui template app.

It results in the Entry (red) not being pushed up in the ScrollView when the keyboard is enabled:

View without keyboard visibleView with keyboard visible

How can I implement the - I guess usually default feature - that the control is being pushed up to be still visible while considering the height of the keyboard (e.g. with/without autocompletion or emoji keyboard)?

Thanks in advance!


Solution

  • To solve this issue, you could obtain keyboard's frame via UIKeyboard.FrameEndUserInfoKey and calculate the height need to change.

    NSValue result = (NSValue)args.Notification.UserInfo.ObjectForKey(new NSString(UIKeyboard.FrameEndUserInfoKey));
    
    CGSize keyboardSize = result.RectangleFValue.Size;
    
    private void Entry_Focused(object sender, FocusEventArgs e)
    {
        if (DeviceInfo.Current.Platform == DevicePlatform.iOS)
        {
           NFloat bottom;
            try
            {
                 UIWindow window = UIApplication.SharedApplication.Delegate.GetWindow();
                    bottom = window.SafeAreaInsets.Bottom;
            }
            catch
            {
                 bottom = 0;
            }
            var heightChange = (keyboardSize.Height - bottom);
            layout.TranslateTo(0, originalTranslationY.Value - heightChange, 50);
        }
    }
    
    private void Entry_Unfocused(object sender, FocusEventArgs e)
    {
        if (DeviceInfo.Current.Platform == DevicePlatform.iOS)
        {
            layout.TranslateTo(0, 0, 50);
        }
    }
    

    Hope it works for you.