visual studio samples prebuilt ejemplos developer apps xamarin xamarin.forms soft-keyboard

studio - Cambiar el retorno para ser la clave siguiente/finalizada en el proyecto compartido de formularios de Xamarin



xamarin prebuilt apps (3)

Aquí hay un enfoque alternativo, pero similar a la solución de SushiHangover. Incluye soporte UWP:

ReturnType.cs en PCL

public enum ReturnType { Go, Next, Done, Send, Search }

BaseEntry.cs en PCL

public class BaseEntry : Entry { // Need to overwrite default handler because we cant Invoke otherwise public new event EventHandler Completed; public static readonly BindableProperty ReturnTypeProperty = BindableProperty.Create( nameof(ReturnType), typeof(ReturnType), typeof(BaseEntry), ReturnType.Done, BindingMode.OneWay ); public ReturnType ReturnType { get { return (ReturnType)GetValue(ReturnTypeProperty); } set { SetValue(ReturnTypeProperty, value); } } public void InvokeCompleted() { if (this.Completed != null) this.Completed.Invoke(this, null); } }

BaseEntryRenderer.cs para Android

public class BaseEntryRenderer : EntryRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); BaseEntry entry = (BaseEntry)this.Element; if(this.Control != null) { if(entry != null) { SetReturnType(entry); // Editor Action is called when the return button is pressed Control.EditorAction += (object sender, TextView.EditorActionEventArgs args) => { if (entry.ReturnType != ReturnType.Next) entry.Unfocus(); // Call all the methods attached to base_entry event handler Completed entry.InvokeCompleted(); }; } } } private void SetReturnType(BaseEntry entry) { ReturnType type = entry.ReturnType; switch (type) { case ReturnType.Go: Control.ImeOptions = ImeAction.Go; Control.SetImeActionLabel("Go", ImeAction.Go); break; case ReturnType.Next: Control.ImeOptions = ImeAction.Next; Control.SetImeActionLabel("Next", ImeAction.Next); break; case ReturnType.Send: Control.ImeOptions = ImeAction.Send; Control.SetImeActionLabel("Send", ImeAction.Send); break; case ReturnType.Search: Control.ImeOptions = ImeAction.Search; Control.SetImeActionLabel("Search", ImeAction.Search); break; default: Control.ImeOptions = ImeAction.Done; Control.SetImeActionLabel("Done", ImeAction.Done); break; } } }

BaseEntryRenderer.cs para iOS

public class BaseEntryRenderer : EntryRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); BaseEntry entry = (BaseEntry)this.Element; if (this.Control != null) { if(entry != null) { SetReturnType(entry); Control.ShouldReturn += (UITextField tf) => { entry.InvokeCompleted(); return true; }; } } } private void SetReturnType(BaseEntry entry) { ReturnType type = entry.ReturnType; switch (type) { case ReturnType.Go: Control.ReturnKeyType = UIReturnKeyType.Go; break; case ReturnType.Next: Control.ReturnKeyType = UIReturnKeyType.Next; break; case ReturnType.Send: Control.ReturnKeyType = UIReturnKeyType.Send; break; case ReturnType.Search: Control.ReturnKeyType = UIReturnKeyType.Search; break; case ReturnType.Done: Control.ReturnKeyType = UIReturnKeyType.Done; break; default: Control.ReturnKeyType = UIReturnKeyType.Default; break; } } }

BaseEntryRenderer.cs para UWP

public class BaseEntryRenderer : EntryRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); BaseEntry entry = (BaseEntry)this.Element; if(this.Control != null) { if(entry != null) { this.Control.KeyDown += (object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs eventArgs) => { if (eventArgs.Key == Windows.System.VirtualKey.Enter) { entry.InvokeCompleted(); // Make sure to set the Handled to true, otherwise the RoutedEvent might fire twice eventArgs.Handled = true; } }; } } } }

En UWP parece que no es posible cambiar la clave de retorno a next / done / ... ExportRenderer agregar los atributos de ExportRenderer para todos los renderizadores personalizados.

Uso

Archivo XAML

<renderer:BaseEntry x:Name="username" Text="Username" ReturnType="Next" /> <renderer:BaseEntry x:Name="password" Text ="Password" IsPassword="true" ReturnType="Done" />

Código detrás del archivo:

this.username.Completed += (object sender, EventArgs e) => this.password.Focus();

Basado en esta source .

¿Es posible cambiar el texto en la tecla ''regresar'' en el teclado para que sea ''siguiente'' o ''listo''? Tengo un formulario de inicio de sesión con nombre de usuario y contraseña. Quiero que la tecla de retorno diga ''siguiente'' cuando esté en el campo de nombre de usuario y luego ''listo'' cuando esté en el campo de contraseña, pero no he visto de ninguna manera hacer esto. Esto es para un proyecto compartido, Android y iOS.


El último paquete de formularios de Xamarin agrega el atributo ReturnType para los elementos de entrada. También ejecutará un comando cuando se haga clic en el botón Hecho. Los tipos de IMEAction para Done, Next, Search, Go y Send ahora son compatibles.


Un EntryRenderer personalizado puede manejar el cambio de la descripción de la tecla de retorno del teclado.

  • iOS: UITextField tiene una propiedad ReturnKeyType que puede establecer en una lista preasignada (ver enumeración UIReturnType ).

  • Android: EntryEditText tiene una propiedad ImeOptions que controla lo que hace el botón "Acción" en el teclado y un método SetImeActionLabel que puede usar para configurar cualquier cadena de texto para él.

Ejemplo de uso del Entry / EntryRenderer personalizado:

new EntryExt { Text = "Next Key", ReturnKeyType = ReturnKeyTypes.Next }, new EntryExt { Text = "Done Key", ReturnKeyType = ReturnKeyTypes.Done }

Una clase de Entry personalizada Xamarin.Forms :

namespace YourNameSpaceHere { public class EntryExt : Entry { public const string ReturnKeyPropertyName = "ReturnKeyType"; public EntryExt() { } public static readonly BindableProperty ReturnKeyTypeProperty = BindableProperty.Create( propertyName: ReturnKeyPropertyName, returnType: typeof(ReturnKeyTypes), declaringType: typeof(EntryExt), defaultValue: ReturnKeyTypes.Done); public ReturnKeyTypes ReturnKeyType { get { return (ReturnKeyTypes)GetValue(ReturnKeyTypeProperty); } set { SetValue(ReturnKeyTypeProperty, value); } } } // Not all of these are support on Android, consult EntryEditText.ImeOptions public enum ReturnKeyTypes : int { Default, Go, Google, Join, Next, Route, Search, Send, Yahoo, Done, EmergencyCall, Continue } }

iOS personalizado EntryRenderer :

[assembly: ExportRenderer(typeof(Entry), typeof(EntryExtRenderer_iOS))] namespace KeyboardDone.iOS { public class EntryExtRenderer_iOS : EntryRenderer { public EntryExtRenderer_iOS() { } protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if ((Control != null) && (e.NewElement != null)) Control.ReturnKeyType = (e.NewElement as EntryExt).ReturnKeyType.GetValueFromDescription(); } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == EntryExt.ReturnKeyPropertyName) { D.WriteLine($"{(sender as EntryExt).ReturnKeyType.ToString()}"); Control.ReturnKeyType = (sender as EntryExt).ReturnKeyType.GetValueFromDescription(); } } } public static class EnumExtensions { public static UIReturnKeyType GetValueFromDescription(this ReturnKeyTypes value) { var type = typeof(UIReturnKeyType); if (!type.IsEnum) throw new InvalidOperationException(); foreach (var field in type.GetFields()) { var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; if (attribute != null) { if (attribute.Description == value.ToString()) return (UIReturnKeyType)field.GetValue(null); } else { if (field.Name == value.ToString()) return (UIReturnKeyType)field.GetValue(null); } } throw new NotSupportedException($"Not supported on iOS: {value}"); } } }

EntryRenderer personalizado de Android:

[assembly: ExportRenderer(typeof(Entry), typeof(EntryExtRenderer_Droid))] namespace KeyboardDone.Droid { public class EntryExtRenderer_Droid : EntryRenderer { public EntryExtRenderer_Droid() { } protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if ((Control != null) && (e.NewElement != null)) { var entryExt = (e.NewElement as EntryExt); Control.ImeOptions = entryExt.ReturnKeyType.GetValueFromDescription(); // This is hackie ;-) / A Android-only bindable property should be added to the EntryExt class Control.SetImeActionLabel(entryExt.ReturnKeyType.ToString(), Control.ImeOptions); } } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == EntryExt.ReturnKeyPropertyName) { var entryExt = (sender as EntryExt); Control.ImeOptions = entryExt.ReturnKeyType.GetValueFromDescription(); // This is hackie ;-) / A Android-only bindable property should be added to the EntryExt class Control.SetImeActionLabel(entryExt.ReturnKeyType.ToString(), Control.ImeOptions); } } } public static class EnumExtensions { public static ImeAction GetValueFromDescription(this ReturnKeyTypes value) { var type = typeof(ImeAction); if (!type.IsEnum) throw new InvalidOperationException(); foreach (var field in type.GetFields()) { var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; if (attribute != null) { if (attribute.Description == value.ToString()) return (ImeAction)field.GetValue(null); } else { if (field.Name == value.ToString()) return (ImeAction)field.GetValue(null); } } throw new NotSupportedException($"Not supported on Android: {value}"); } } }