Change return to be next/done key in Xamarin Forms Shared Project

后端 未结 4 1709
北海茫月
北海茫月 2020-12-13 18:53

Is it possible to change the text in the \'return\' key on the keyboard to be either \'next\' or \'done\'? I have a login form with username and password. I want the return

相关标签:
4条回答
  • 2020-12-13 19:17

    Yes latest Xamarin Forms allowed directly ReturnType as property, just need to add ReturnType in Xaml

     <Entry x:Name="myEntry" ReturnType="Done"/>
    
    0 讨论(0)
  • 2020-12-13 19:31

    Here is an alternative approach, but similar to the solution of SushiHangover. It includes UWP support:

    ReturnType.cs in PCL

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

    BaseEntry.cs in 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 for 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 for 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 for 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;
                        }
                    };
                }
            }
        }
    }
    

    On UWP it seems not be possible to change the return key to next/done/... You need to add ExportRenderer attributes yourself for all custom renderers.

    Usage

    XAML file

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

    Code behind file:

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

    Based on this source.

    0 讨论(0)
  • 2020-12-13 19:34

    A custom EntryRenderer can handle changing the keyboard return key description.

    • iOS : UITextField has a ReturnKeyType property that you can set to a preassigned list (see UIReturnType enum).

    • Android : EntryEditText has a ImeOptions property that controls what the "Action" button on the keyboard does and a SetImeActionLabel method that you can use to set any text string for it.

    Usage Example of the custom Entry/EntryRenderer:

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

    A Xamarin.Forms custom Entry class:

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

    Android custom EntryRenderer:

    [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}");
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-13 19:40

    The latest Xamarin Forms package adds the ReturnType attribute for Entry elements. It will also execute a command when the Done button is clicked. The IMEAction types for Done, Next, Search, Go and Send are all supported now.

    0 讨论(0)
提交回复
热议问题