diff --git a/doc/helpers/Input-extensions.md b/doc/helpers/Input-extensions.md index 6eaf913e2..8874f6f67 100644 --- a/doc/helpers/Input-extensions.md +++ b/doc/helpers/Input-extensions.md @@ -8,13 +8,14 @@ Provides various attached properties for _input controls_, such as `TextBox` and ## Attached Properties -| Property | Type | Description | -|------------------------|-----------|--------------------------------------------------------------------------------------------| -| `AutoDismiss` | `bool` | Whether the soft-keyboard will be dismissed when the enter key is pressed. | -| `AutoFocusNext` | `bool` | Whether the focus will move to the next focusable element when the enter key is pressed.\* | -| `AutoFocusNextElement` | `Control` | Sets the next control to focus when the enter key is pressed.\* | +| Property | Type | Description | +|------------------------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------| +| `AutoDismiss` | `bool` | Whether the soft keyboard will be dismissed when the enter key is pressed. | +| `AutoFocusNext` | `bool` | Whether the focus will move to the next focusable element when the enter key is pressed.\* | +| `AutoFocusNextElement` | `Control` | Sets the next control to focus when the enter key is pressed.\* | +| `ReturnType` | `ReturnType` | The type of return button on a soft keyboard for Android/iOS. It can be one of the following options: __Default, Done, Go, Next, Search, Send__. | -`AutoFocusNext` and `AutoFocusNextElement`\*: Having either or both of the two properties set will enable the focus next behavior. `AutoFocusNextElement` will take precedences over `AutoFocusNext` when both are set. +`AutoFocusNext` and `AutoFocusNextElement`\*: Having either or both of the two properties set will enable the focus next behavior. `AutoFocusNextElement` will take precedence over `AutoFocusNext` when both are set. ### Remarks @@ -35,6 +36,9 @@ xmlns:utu="using:Uno.Toolkit.UI" - + + + + ``` diff --git a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/InputExtensionsSamplePage.xaml b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/InputExtensionsSamplePage.xaml index 3e72a9152..c12597a6a 100644 --- a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/InputExtensionsSamplePage.xaml +++ b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/InputExtensionsSamplePage.xaml @@ -31,10 +31,20 @@ - + + + + + + + + + + + diff --git a/src/Uno.Toolkit.UI/Behaviors/InputExtensions.cs b/src/Uno.Toolkit.UI/Behaviors/InputExtensions.cs index 44f1f9f7b..c56d38203 100644 --- a/src/Uno.Toolkit.UI/Behaviors/InputExtensions.cs +++ b/src/Uno.Toolkit.UI/Behaviors/InputExtensions.cs @@ -11,6 +11,12 @@ using Windows.System; using Windows.UI.ViewManagement; +#if __ANDROID__ +using Android.Views.InputMethods; +#elif __IOS__ +using UIKit; +#endif + #if IS_WINUI using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -27,10 +33,36 @@ public static class InputExtensions { private static readonly ILogger _logger = typeof(InputExtensions).Log(); + public enum ReturnType { + Default, + Done, + Go, + Next, + Search, + Send + } + + #region DependencyProperty: ReturnType + + /// + /// Backing property for what type of return the soft keyboard will show. + /// + public static DependencyProperty ReturnTypeProperty { [DynamicDependency(nameof(GetReturnType))] get; } = DependencyProperty.RegisterAttached( + "ReturnType", + typeof(ReturnType), + typeof(InputExtensions), + new PropertyMetadata(ReturnType.Default, OnReturnTypeChanged)); + + [DynamicDependency(nameof(SetReturnType))] + public static ReturnType GetReturnType(DependencyObject obj) => (ReturnType)obj.GetValue(ReturnTypeProperty); + [DynamicDependency(nameof(GetReturnType))] + public static void SetReturnType(DependencyObject obj, ReturnType value) => obj.SetValue(ReturnTypeProperty, value); + + #endregion #region DependencyProperty: AutoDismiss /// - /// Backing property for whether the soft-keyboard will be dismissed when the enter key is pressed. + /// Backing property for whether the soft keyboard will be dismissed when the enter key is pressed. /// public static DependencyProperty AutoDismissProperty { [DynamicDependency(nameof(GetAutoDismiss))] get; } = DependencyProperty.RegisterAttached( "AutoDismiss", @@ -109,6 +141,40 @@ internal static bool IsEnterCommandSupportedFor(DependencyObject host) return host is TextBox || host is PasswordBox; } + private static void OnReturnTypeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + if (sender is TextBox || sender is PasswordBox) + { + if (e.NewValue is not ReturnType returnType) + { + returnType = ReturnType.Default; + } +#if __ANDROID__ + ImeAction imeAction = GetImeActionFromReturnType(returnType); + + if (sender is TextBox textBox) + { + textBox.ImeOptions = imeAction; + } + else if (sender is PasswordBox passwordBox) + { + passwordBox.ImeOptions = imeAction; + } +#elif __IOS__ + UIReturnKeyType returnKeyType = GetReturnKeyTypeFromReturnType(returnType); + + if (sender is TextBox textBox) + { + textBox.ReturnKeyType = returnKeyType; + } + else if (sender is PasswordBox passwordBox) + { + passwordBox.ReturnKeyType = returnKeyType; + } +#endif + } + } + private static void OnAutoDismissChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) => UpdateSubscription(sender); private static void OnAutoFocusNextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) => UpdateSubscription(sender); private static void OnAutoFocusNextElementChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) => UpdateSubscription(sender); @@ -177,5 +243,29 @@ private static void OnUIElementKeyUp(object sender, KeyRoutedEventArgs e) _ => default, }; } + +#if __ANDROID__ + private static ImeAction GetImeActionFromReturnType(ReturnType returnType) => returnType switch + { + ReturnType.Next => ImeAction.Next, + ReturnType.Go => ImeAction.Go, + ReturnType.Search => ImeAction.Search, + ReturnType.Send => ImeAction.Send, + ReturnType.Done => ImeAction.Done, + ReturnType.Default or _ => ImeAction.Unspecified + }; +#endif + +#if __IOS__ + private static UIReturnKeyType GetReturnKeyTypeFromReturnType(ReturnType returnType) => returnType switch + { + ReturnType.Next => UIReturnKeyType.Next, + ReturnType.Go => UIReturnKeyType.Go, + ReturnType.Search => UIReturnKeyType.Search, + ReturnType.Send => UIReturnKeyType.Send, + ReturnType.Done => UIReturnKeyType.Done, + ReturnType.Default or _ => UIReturnKeyType.Default + }; +#endif } }