Browse Source

Android soft input using Avalonia.Input

ili 4 years ago
parent
commit
12c2c16d13

+ 1 - 1
global.json

@@ -1,6 +1,6 @@
 {
 	"sdk": {
-		"version": "3.1.407"
+		"version": "3.1.401"
 	},
     "msbuild-sdks": {
         "Microsoft.Build.Traversal": "1.0.43",

+ 1 - 1
samples/ControlCatalog/Pages/TextBoxPage.xaml

@@ -13,7 +13,7 @@
       <StackPanel Orientation="Vertical" Spacing="8">
         <TextBox Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit." Width="200" />
         <TextBox Width="200" Watermark="ReadOnly" IsReadOnly="True" Text="This is read only"/>
-        <TextBox Width="200" Watermark="Watermark" InputType="Numeric" />
+        <TextBox Width="200" Watermark="Numeric Watermark" x:Name="numericWatermark"/>
         <TextBox Width="200"
                  Watermark="Floating Watermark"
                  UseFloatingWatermark="True"

+ 6 - 0
samples/ControlCatalog/Pages/TextBoxPage.xaml.cs

@@ -13,6 +13,12 @@ namespace ControlCatalog.Pages
         private void InitializeComponent()
         {
             AvaloniaXamlLoader.Load(this);
+
+            this.Get<TextBox>("numericWatermark")
+                .TextInputOptionsQuery += (s, a) =>
+                {
+                    a.ContentType = Avalonia.Input.TextInput.TextInputContentType.Number;
+                };
         }
     }
 }

+ 46 - 1
src/Android/Avalonia.Android/AndroidInputMethod.cs

@@ -5,6 +5,8 @@ using Android.Content;
 using Android.Runtime;
 using Android.Views;
 using Android.Views.InputMethods;
+using Avalonia.Controls.Platform;
+using Avalonia.Input;
 using Avalonia.Input.TextInput;
 
 namespace Avalonia.Android
@@ -14,6 +16,7 @@ namespace Avalonia.Android
     {
         private readonly TView _host;
         private readonly InputMethodManager _imm;
+        private IInputElement _inputElement;
 
         public AndroidInputMethod(TView host)
         {
@@ -44,7 +47,49 @@ namespace Avalonia.Android
 
         public void SetOptions(TextInputOptionsQueryEventArgs options)
         {
-            //throw new NotImplementedException();
+            if (_inputElement != null)
+            {
+                _inputElement.PointerReleased -= RestoreSoftKeyboard;
+            }
+
+            _inputElement = options.Source as InputElement;
+
+            if (_inputElement == null)
+            {
+                _imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.None);
+            }
+
+            _host.InitEditorInfo((outAttrs) =>
+            {
+                outAttrs.InputType = options.ContentType switch
+                {
+                    TextInputContentType.Email => global::Android.Text.InputTypes.TextVariationEmailAddress,
+                    TextInputContentType.Number => global::Android.Text.InputTypes.ClassNumber,
+                    TextInputContentType.Password => global::Android.Text.InputTypes.TextVariationPassword,
+                    TextInputContentType.Phone => global::Android.Text.InputTypes.ClassPhone,
+                    TextInputContentType.Url => global::Android.Text.InputTypes.TextVariationUri,
+                    _ => global::Android.Text.InputTypes.Null
+                };
+
+                if (options.AutoCapitalization)
+                {
+                    outAttrs.InitialCapsMode = global::Android.Text.CapitalizationMode.Sentences;
+                    outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagCapSentences;
+                }
+
+                if (options.Multiline)
+                    outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagMultiLine;
+            });
+
+            Reset();
+            _inputElement.PointerReleased += RestoreSoftKeyboard;
+            RestoreSoftKeyboard(null, null);
+        }
+
+        private void RestoreSoftKeyboard(object sender, PointerReleasedEventArgs e)
+        {
+            //_imm.ToggleSoftInput(ShowFlags.Implicit, HideSoftInputFlags.NotAlways);
+            _imm.ShowSoftInput(_host, ShowFlags.Implicit);
         }
     }
 }

+ 0 - 1
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@@ -16,7 +16,6 @@ namespace Avalonia.Android
     public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle
     {
         bool _invalidateQueued;
-        private ISoftInputElement _softInputElement;
         readonly object _lock = new object();
         private readonly Handler _handler;
 

+ 1 - 5
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@@ -35,7 +35,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
         {
             _view = new ViewImpl(context, this, placeOnTop);
             _textInputMethod = new AndroidInputMethod<ViewImpl>(_view);
-            _keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this);
+            _keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this, _textInputMethod);
             _touchHelper = new AndroidTouchEventsHelper<TopLevelImpl>(this, () => InputRoot,
                 GetAvaloniaPointFromEvent);
 
@@ -237,9 +237,5 @@ namespace Avalonia.Android.Platform.SkiaPlatform
         {
             throw new NotImplementedException();
         }
-        public void InitEditorInfo(Action<EditorInfo> init)
-        {
-            _view.InitEditorInfo(init);
-        }
     }
 }

+ 8 - 70
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs

@@ -12,19 +12,22 @@ using Avalonia.Controls;
 using Avalonia.Controls.Platform;
 using Avalonia.Input;
 using Avalonia.Input.Raw;
+using Avalonia.Input.TextInput;
 
 namespace Avalonia.Android.Platform.Specific.Helpers
 {
-    internal class AndroidKeyboardEventsHelper<TView> : IDisposable where TView : TopLevelImpl, IAndroidView, ITopLevelImplWithTextInputMethod
+    internal class AndroidKeyboardEventsHelper<TView> : IDisposable where TView : TopLevelImpl, IAndroidView
     {
-        private TView _view;
+        private readonly TView _view;
+        private readonly ITextInputMethodImpl _textInpuMethod;
         private IInputElement _lastFocusedElement;
 
         public bool HandleEvents { get; set; }
 
-        public AndroidKeyboardEventsHelper(TView view)
+        public AndroidKeyboardEventsHelper(TView view, ITextInputMethodImpl androidTextInput)
         {
-            this._view = view;
+            _view = view;
+            _textInpuMethod = androidTextInput;
             HandleEvents = true;
         }
 
@@ -100,71 +103,6 @@ namespace Avalonia.Android.Platform.Specific.Helpers
             return rv;
         }
 
-        private bool NeedsKeyboard(IInputElement element)
-        {
-            //may be some other elements
-            return element is ISoftInputElement;
-        }
-
-        private void TryShowHideKeyboard(ISoftInputElement element, bool value)
-        {
-            _view.InitEditorInfo((outAttrs) =>
-            {
-                outAttrs.InputType = element.InputType switch
-                {
-                    InputType.Numeric => global::Android.Text.InputTypes.ClassNumber,
-                    InputType.Phone => global::Android.Text.InputTypes.ClassPhone,
-                    _ => global::Android.Text.InputTypes.Null
-                };
-            });
-
-            var input = _view.View.Context.GetSystemService(Context.InputMethodService).JavaCast<InputMethodManager>();
-
-            if (value && element != null && element.InputType != InputType.None)
-            {
-                _view.View.RequestFocus();
-
-                if (!ReferenceEquals(_lastFocusedElement, element))
-                {
-                    input.RestartInput(_view.View);
-                }
-
-                input.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.NotAlways);
-            }
-            else
-            {
-                input.HideSoftInputFromWindow(_view.View.WindowToken, HideSoftInputFlags.None);
-            }
-        }
-
-        public void UpdateKeyboardState(IInputElement element)
-        {
-            var focusedElement = element as ISoftInputElement;
-            var lastElement = _lastFocusedElement as ISoftInputElement;
-            
-            bool oldValue = lastElement?.InputType > InputType.None;
-            bool newValue = focusedElement?.InputType > InputType.None;
-
-            if (newValue != oldValue || newValue)
-            {
-                if (_lastFocusedElement != null)
-                    _lastFocusedElement.PointerReleased -= RestoreSoftKeyboard;
-
-                TryShowHideKeyboard(focusedElement, newValue);
-
-                if (newValue && focusedElement != null)
-                    element.PointerReleased += RestoreSoftKeyboard;
-            }
-
-            _lastFocusedElement = element;
-        }
-
-        private void RestoreSoftKeyboard(object sender, PointerReleasedEventArgs e)
-        {
-            if (_lastFocusedElement is ISoftInputElement softInputElement && softInputElement.InputType != InputType.None)
-                TryShowHideKeyboard(softInputElement, true);
-        }
-
         public void ActivateAutoShowKeyboard()
         {
             var kbDevice = (KeyboardDevice.Instance as INotifyPropertyChanged);
@@ -178,7 +116,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
         {
             if (e.PropertyName == nameof(KeyboardDevice.FocusedElement))
             {
-                UpdateKeyboardState(KeyboardDevice.Instance.FocusedElement);
+                //UpdateKeyboardState(KeyboardDevice.Instance.FocusedElement);
             }
         }
 

+ 0 - 2
src/Android/Avalonia.Android/Platform/Specific/IAndroidView.cs

@@ -6,7 +6,5 @@ namespace Avalonia.Android.Platform.Specific
     public interface IAndroidView
     {
         View View { get; }
-
-
     }
 }

+ 1 - 8
src/Avalonia.Controls/TextBox.cs

@@ -18,7 +18,7 @@ using Avalonia.Controls.Metadata;
 namespace Avalonia.Controls
 {
     [PseudoClasses(":empty")]
-    public class TextBox : TemplatedControl, UndoRedoHelper<TextBox.UndoRedoState>.IUndoRedoHost, ISoftInputElement
+    public class TextBox : TemplatedControl, UndoRedoHelper<TextBox.UndoRedoState>.IUndoRedoHost
     {
         public static KeyGesture CutGesture { get; } = AvaloniaLocator.Current
             .GetService<PlatformHotkeyConfiguration>()?.Cut.FirstOrDefault();
@@ -130,11 +130,6 @@ namespace Avalonia.Controls
                         nameof(CanPaste),
                         o => o.CanPaste);
 
-        public static readonly DirectProperty<TextBox, InputType> InputTypeProperty =
-            AvaloniaProperty.RegisterDirect<TextBox, InputType>(
-                    nameof(InputType),
-                    o => o.InputType);
-
         struct UndoRedoState : IEquatable<UndoRedoState>
         {
             public string Text { get; }
@@ -1248,7 +1243,5 @@ namespace Avalonia.Controls
                 ClearSelection();
             }
         }
-
-        public InputType InputType { get; set; } = InputType.Text;
     }
 }

+ 0 - 11
src/Avalonia.Input/ISoftInputElement.cs

@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Avalonia.Input
-{
-    public interface ISoftInputElement
-    {
-        InputType InputType { get; }
-    }
-}

+ 0 - 32
src/Avalonia.Input/InputType.cs

@@ -1,32 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Avalonia.Input
-{
-    /// <summary>
-    /// Input type enumeration
-    /// </summary>
-    public enum InputType
-    {
-        /// <summary>
-        /// Do not use input
-        /// </summary>
-        None,
-
-        /// <summary>
-        /// User full text input
-        /// </summary>
-        Text,
-
-        /// <summary>
-        /// Use numeric text input
-        /// </summary>
-        Numeric,
-
-        /// <summary>
-        /// Use phone input
-        /// </summary>
-        Phone
-    }
-}