Search code examples
keyboardfocusmaui

.Net Maui Android cannot hide keyboard


UPDATED - Trimmed down user control:

using CommunityToolkit.Maui.Core.Platform;
using CommunityToolkit.Mvvm.Input;
using System.Diagnostics;

namespace GSL.Presentation.CustomControls;

public partial class GSLEntryControl : ContentView
{

public GSLEntryControl()
{
    try
    {
        InitializeComponent();
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"GEORGE: Exception: {ex}");
    }
}

[RelayCommand]
private void ClearText()
{
    Text = string.Empty;
}


// All the updates will be done in the property set. 
public static readonly BindableProperty IsInFocusProperty = BindableProperty.Create(
    nameof(IsInFocus),
    typeof(bool),
    typeof(GSLEntryControl),
    false,
    BindingMode.OneWay,
    propertyChanged: (bindable, oldValue, newValue) =>
    {
        Debug.WriteLine("George: IsInFocusProperty Start");
        if (bindable is GSLEntryControl editText)
        {
            editText.IsInFocus = (bool)newValue;
        }
        Debug.WriteLine("George: IsInFocusProperty End");
    });

public string _text = string.Empty;
public string Text
{
    get
    {
        return _text;
    }
    set
    {
        //Run all this code on the main UI Thread 
        Application.Current.Dispatcher.Dispatch(() =>
        {
            Debug.WriteLine("GEORGE: Text Set Start");
            _text = value;
            //IsClearButtonVisible = _text?.Length > 0;
            //SetBorderColor();
            Debug.WriteLine("GEORGE: Text Set End");
        });
    }
}


private bool _isInFocus = false;
public bool IsInFocus
{
    get
    {
        return _isInFocus;
    }
    set
    {
        Debug.WriteLine($"GEORGE: IsInFocus Set Start.  Value: {value}");
        _isInFocus = value;

        Application.Current.Dispatcher.Dispatch(async () =>
        {

            if (_isInFocus)
            {
                var tempResult = gslEntry.Focus();

            

    Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
                    {
#if ANDROID
                        handler.PlatformView.ShowSoftInputOnFocus = false;
#endif
                    });
                //var workResult = await gslEntry.HideSoftInputAsync(CancellationToken.None);
                //Debug.WriteLine($"GEORGE: Focus ShowKeyboard Result: {workResult}");

                Debug.WriteLine($"GEORGE: Focus-KeyBoardShown: {gslEntry.IsSoftKeyboardShowing()}" );
            }
            else
            {
                gslEntry.Unfocus();
            }
            //SetBorderColor();
            Debug.WriteLine("GEORGE: IsInFocus Set End");
        });
    }
}

//When entry is focused, change border color to blue
async void Entry_Focused(object sender, FocusEventArgs e)
{
    Debug.WriteLine("GEORGE: Entry_Focused start");
    //EntryFocused?.Invoke(sender, e);

    bool workResult = false;
    Application.Current.Dispatcher.Dispatch(async () =>
    {
        workResult = await gslEntry.HideSoftInputAsync(CancellationToken.None);
        Debug.WriteLine($"GEORGE: Focus ShowKeyboard Result: {workResult}");
    });

    Debug.WriteLine("GEORGE: Entry_Focused end");
}

}

Here is the XAML for the control:

<ContentView.Resources>
    <ResourceDictionary>
        <mct:InvertedBoolConverter x:Key="InvertedBoolConverter"/>
    </ResourceDictionary>

</ContentView.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>

    <Border x:Name="entryFrame"
            StrokeThickness="2"
            Padding="0"
            HeightRequest="50"
            VerticalOptions="CenterAndExpand"
            HorizontalOptions="FillAndExpand" 
            Grid.Row="0"
            Grid.Column="0"
            Grid.ColumnSpan="2">

        <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ColumnDefinitions="*,auto">
            <Entry x:Name="gslEntry"
                       Margin="10,0,0,0"
                       ReturnType="Done"
                       Keyboard="Text"
                       TextTransform="Uppercase"
                       FontSize="16"
                       Text="{Binding Text,Mode=TwoWay}"
                       IsEnabled="True"
                       Placeholder=""
                       IsPassword="False"
                       VerticalOptions="CenterAndExpand"
                       HorizontalOptions="FillAndExpand"
                   Grid.Column="0"/>


            <!-- Clear Button -->
            <ImageButton Source="ic_delete.xml"
                     x:Name="clearButton"
                     WidthRequest="32"
                     HeightRequest="32"
                     VerticalOptions="Center"
                     HorizontalOptions="End"
                     Margin="0,0,5,0"
                     Command="{Binding ClearTextCommand}"
                     Grid.Column="1"/>
        </Grid>
    </Border>

    <Label x:Name="invalidLabel"
           Text="Error"
           Margin="5,0,0,0"
           HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
           IsVisible="false"
           Style="{StaticResource ValidationErrorLabelStyle}"
           Grid.Row="1"/>
</Grid>

I have code in the IsInFocus event to hide the keyboard when an entry control gets focus. I have tried it several ways including using HideSoftInputAsync(CancellationToken.None) on the entry control

Using a handler for Android to hide the keyboard as see in the current code. Neither of these are working.

I also tried adding and removing async from the Dispatcher and event completely removing the Dispatcher and they had no effect.


Solution

  • You can use the handler to hide the softkeyboard.

    First, you need to create a custom Entry.

    public class NoKeyBoardEntry:Entry{
    
    
    }
    

    Second, you can add the handler to the GSLEntryControl.xaml.cs to hide the keyboard when you get focus of the.

     public partial class GSLEntryControl : ContentView
        {
        
            public GSLEntryControl()
            {
                InitializeComponent();
                NokeyBoard();           
            }
        
        void NokeyBoard()
            {
                Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
                {
                    if (view is NoKeyBoardEntry)
                    {
        #if ANDROID
                        handler.PlatformView.ShowSoftInputOnFocus = false;
        
        #endif
                    }
                });
            }
        }
    

    Last, you can create the custom entry like this.

    <ContentPage
    
    ...
    xmlns:local="clr-namespace:yourProject"
    >
    
    <local:NoKeyBoardEntry>