.Net Maui Android 无法隐藏键盘

问题描述 投票:0回答:1

我有以下用户控件:

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

namespace GSL.Presentation.CustomControls;

public partial class GSLEntryControl : ContentView
{
    private static Color blue;
    private static Color red;
    private static Color gray;
    public event EventHandler EntryCompleted;
    public event EventHandler EntryFocused;
    public event EventHandler EntryUnfocused;
    private bool isFirstDisplay = true;

    public GSLEntryControl()
    {
        try
        {
            InitializeComponent();
            bool redExists = Application.Current.Resources.TryGetValue("alert_red", out object redValue);
            bool blueExists = Application.Current.Resources.TryGetValue("action_color", out object blueValue);
            bool grayExists = Application.Current.Resources.TryGetValue("Gray200", out object grayValue);

            red = redExists ? (Color)redValue : Colors.Gray;
            blue = blueExists ? (Color)blueValue : Colors.Gray;
            gray = grayExists ? (Color)grayValue : Colors.Gray;

            BorderColor = Color.FromArgb("ffc8c8c8");
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"GEORGE: Exception: {ex}");
        }
    }

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

    public static readonly BindableProperty TextProperty = BindableProperty.Create(
        nameof(Text),
        typeof(string),
        typeof(GSLEntryControl),
        string.Empty,
        defaultBindingMode: BindingMode.TwoWay,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            if (bindable is GSLEntryControl editText)
            {
                editText.Text = newValue?.ToString();
            }
        });

    public static readonly BindableProperty ErrorTextProperty = BindableProperty.Create(
        nameof(ErrorText),
        typeof(string),
        typeof(GSLEntryControl),
        string.Empty,
        defaultBindingMode: BindingMode.TwoWay);

    public static readonly BindableProperty PlaceholderTextProperty = BindableProperty.Create(
        nameof(PlaceholderText),
        typeof(string),
        typeof(GSLEntryControl),
        string.Empty,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            if (bindable is GSLEntryControl editText)
            {
                editText.PlaceholderText = (string)newValue;
            }
        });


    public static readonly BindableProperty IsPasswordProperty = BindableProperty.Create(
        nameof(IsPassword),
        typeof(bool),
        typeof(GSLEntryControl),
        false,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            if (bindable is GSLEntryControl editText)
            {
                editText.IsPassword = (bool)newValue;
            }
        });

    public static readonly BindableProperty IsEntryEnabledProperty = BindableProperty.Create(
        nameof(IsEntryEnabled),
        typeof(bool),
        typeof(GSLEntryControl),
        true,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            Debug.WriteLine("George: IsEntryEnabled Start");
            if (bindable is GSLEntryControl editText)
            {
                editText.IsEntryEnabled = (bool)newValue;
            }
            Debug.WriteLine("George: IsEntryEnabled End");
        });

    public static readonly BindableProperty IsValidProperty = BindableProperty.Create(
        nameof(IsValid),
        typeof(bool),
        typeof(GSLEntryControl),
        true,
        BindingMode.TwoWay,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            Debug.WriteLine("GEORGE: IsValidProperty Set Start");
            if (bindable is GSLEntryControl editText)
            {
                editText.IsValid = (bool)newValue;
            }
            Debug.WriteLine("GEORGE: IsValidProperty Set End");
        });

    // 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 static readonly BindableProperty KeyboardModeProperty = BindableProperty.Create(
        nameof(KeyboardMode),
        typeof(Keyboard),
        typeof(GSLEntryControl),
        Keyboard.Default,
        BindingMode.OneWay,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            if (bindable is GSLEntryControl editText)
            {
                editText.KeyboardMode = (Keyboard)newValue;
            }
        });



    public static readonly BindableProperty KeyboardDisplayModeProperty = BindableProperty.Create(
        nameof(KeyboardDisplayMode),
        typeof(KeyboardDisplayModeOptions),
        typeof(GSLEntryControl),
        KeyboardDisplayModeOptions.Always,
        BindingMode.OneWay,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            if (bindable is GSLEntryControl editText)
            {
                editText.KeyboardDisplayMode = (KeyboardDisplayModeOptions)newValue;
            }
        });



    public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create(
        nameof(MaxLength),
        typeof(int),
        typeof(GSLEntryControl),
        100,
        BindingMode.OneWay,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            if (bindable is GSLEntryControl editText)
            {
                editText.MaxLength = (int)newValue;
            }
        });

    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");
            });
        }
    }

    public string errorText = string.Empty;
    public string ErrorText
    {
        get
        {
            return errorText;
        }
        set
        {
            Application.Current.Dispatcher.Dispatch(() =>
            {
                errorText = value;
                invalidLabel.Text = errorText;
            });
        }
    }

    Color _borderColor = Color.FromArgb("ffc8c8c8");
    private Color BorderColor
    {
        get
        {
            return _borderColor;
        }
        set
        {
            Application.Current.Dispatcher.Dispatch(() =>
            {
                _borderColor = value;
                entryFrame.Stroke = value;
            });
        }
    }

    public string _placeholderText = string.Empty;
    public string PlaceholderText
    {
        get
        {
            return _placeholderText;
        }
        set
        {
            Application.Current.Dispatcher.Dispatch(() =>
            {
                _placeholderText = value;
                gslEntry.Placeholder = _placeholderText;
            });
        }
    }

    public bool _isPassword = false;
    public bool IsPassword
    {
        get
        {
            return _isPassword;
        }

        set
        {
            Application.Current.Dispatcher.Dispatch(() =>
            {
                _isPassword = value;
                gslEntry.IsPassword = _isPassword;
            });
        }
    }

    public bool _isEntryEnabled = true;
    public bool IsEntryEnabled
    {
        get
        {
            return _isEntryEnabled;
        }
        set
        {
            Application.Current.Dispatcher.Dispatch(() =>
            {
                Debug.WriteLine($"GEORGE: IsEntryEnabled Set Start. Value {value}");
                _isEntryEnabled = value;
                gslEntry.IsEnabled = _isEntryEnabled;
                SetBorderColor();
                Debug.WriteLine("GEORGE: IsEntryEnabled Set End");
            });
        }
    }

    bool _isClearButtonVisible = false;
    private bool IsClearButtonVisible
    {
        get
        {
            return _isClearButtonVisible;
        }
        set
        {
            Application.Current.Dispatcher.Dispatch(() =>
            {
                _isClearButtonVisible = value;
                clearButton.IsVisible = _isClearButtonVisible;
            });
        }
    }

    private bool _isValid = true;
    public bool IsValid
    {
        get
        {
            return _isValid;
        }
        set
        {
            Debug.WriteLine("GEORGE: IsValid Set Start");
            _isValid = value;
            invalidLabel.IsVisible = !_isValid; 
            SetBorderColor();
            Debug.WriteLine("GEORGE: IsValid 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();
                    Debug.WriteLine($"GEORGE: Focus Result: {tempResult}");
                }
                else
                {
                    gslEntry.Unfocus();
                }
                SetBorderColor();
                Debug.WriteLine("GEORGE: IsInFocus Set End");
            });
        }
    }

    private void SetBorderColor()
    {
        Application.Current.Dispatcher.Dispatch(() =>
        {
            if (IsInFocus && IsEntryEnabled)
            {
                BorderColor = IsValid ? blue : red;
            }
            else
            {
                BorderColor = gray;
            }
        });
    }

    private Keyboard _keyboardMode = Keyboard.Plain;
    public Keyboard KeyboardMode
    {
        get
        {
            return _keyboardMode;
        }
        set
        {
            Application.Current.Dispatcher.Dispatch(() =>
            {
                _keyboardMode = value;
                gslEntry.Keyboard = _keyboardMode;
            });
        }
    }


    private KeyboardDisplayModeOptions _keyboardDisplayMode = KeyboardDisplayModeOptions.Always;
    public KeyboardDisplayModeOptions KeyboardDisplayMode
    {
        get
        {
            return _keyboardDisplayMode;
        }
        set
        {
            _keyboardDisplayMode = value;
        }
    }

    private int _maxLength = 0;
    public int MaxLength
    {
        get
        {
            return _maxLength;
        }
        set
        {
            Application.Current.Dispatcher.Dispatch(() =>
            {
                _maxLength = value;
                gslEntry.MaxLength = _maxLength;
            });

        }
    }


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

        Application.Current.Dispatcher.Dispatch(async () =>
        {
            Debug.WriteLine("GEORGE: ProcessKeyboard start");
            Debug.WriteLine($"GEORGE IsInFocus: {IsInFocus}");
            Debug.WriteLine($"GEORGE gslEntry.IsSoftKeyboardShowing(): {gslEntry.IsSoftKeyboardShowing()} ");
            Debug.WriteLine($"GEORGE KeyboardDisplayMode: {KeyboardDisplayMode} ");
            Debug.WriteLine($"GEORGE isFirstDisplay: {isFirstDisplay} ");

            //Now set the keyboard accordingly. 
            if (KeyboardDisplayMode == KeyboardDisplayModeOptions.Always ||
                (KeyboardDisplayMode == KeyboardDisplayModeOptions.AfterFirstEntry && !isFirstDisplay))
            {
                var result = await gslEntry.ShowSoftInputAsync(CancellationToken.None);
                Debug.WriteLine($"GEORGE: Focus ShowKeyboard Result: {result}");
            }
            else
            {

                bool workResult = false;
                //We know we are in the focus and the keyboard should come up.  If we try to hide it and it fails keep trying - for up to 10 seconds - until it hides
                workResult = await gslEntry.HideSoftInputAsync(CancellationToken.None);

                Debug.WriteLine($"GEORGE: Focus HideKeyboard Result: {workResult}");

                if (gslEntry.IsSoftKeyboardShowing())
                {
                    isFirstDisplay = false;
                }
            }
            Debug.WriteLine("GEORGE: ProcessKeyboard end");
        });

        SetBorderColor();

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

    //When entry is not in focus, change border color to gray
    void Entry_Unfocused(object sender, FocusEventArgs e)
    {
        Debug.WriteLine("GEORGE: Entry_UnFocused start");

        clearButton.IsVisible = false;
        EntryUnfocused?.Invoke(sender, e);

        SetBorderColor();
        Debug.WriteLine("GEORGE: Entry_UnFocused end");
    }

    //When entry is completed, run custom event
    void Entry_Completed(object sender, EventArgs e)
    {
        EntryCompleted?.Invoke(sender, e);
    }

    public enum KeyboardDisplayModeOptions
    {
        Never = 0,
        AfterFirstEntry = 1,
        Always = 2
    }
}

这是控件的 XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:GSL.Presentation.CustomControls"
             xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="GSL.Presentation.CustomControls.GSLEntryControl"
             x:DataType="controls:GSLEntryControl"
             x:Name="customEntry">

    <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"
                           Completed="Entry_Completed"
                           Focused="Entry_Focused"
                           Unfocused="Entry_Unfocused"
                           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="{Binding ErrorText, Source={x:Reference customEntry}}"
               Margin="5,0,0,0"
               HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
               IsVisible="false"
               Style="{StaticResource ValidationErrorLabelStyle}"
               Grid.Row="1"/>
    </Grid>
</ContentView>

在 Entry 控件的 Entry_Focused 事件中 - 我尝试根据 KeyboardDisplayMode 的设置隐藏软键盘。 挑战在于应用程序似乎从未检测到键盘可见,因为 gslEntry.IsSoftKeyboardShowing() 始终返回 false。

这表明键盘可能在其他事件之后显示? 我只是想弄清楚在哪里放置我的代码,以便我可以隐藏软键盘。 条目控件曾经位于堆栈布局内,我读到条目与它配合得不好,所以我将所有内容都放在网格内。 不幸的是,这没有效果。

我还尝试从调度程序中删除异步,并完全删除调度程序的事件,但它们没有效果。

将以下内容添加到页面来测试自己

xmlns:controls="clr-namespace:GSL.Presentation.CustomControls"

  



 <controls:GSLEntryControl x:Name="ULDIDInput" MaxLength="12" Text="" ErrorText="Bad Input" 
                                  IsInFocus="True"  IsEntryEnabled="True" KeyboardDisplayMode="AfterFirstEntry"
                                  EntryCompleted="ULDIDInput_EntryCompleted"  IsValid="True" HorizontalOptions="EndAndExpand" WidthRequest="200" 
                                  PlaceholderText="Scan or Key Enter"/>

如有任何帮助,我们将不胜感激。

keyboard focus maui
1个回答
0
投票

您可以使用处理程序来隐藏软键盘。

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
        {
#if ANDROID
            handler.PlatformView.ShowSoftInputOnFocus = false;
#endif
        });
© www.soinside.com 2019 - 2024. All rights reserved.