How to change 'Show on-screen keyboard' While using hardware keyboard for the .Droid device

TobyKTobyK GBMember ✭✭✭

We've got a xamarin forms app with various entry cells. We are using a Bluetooth scanning device paired with the device. When focus is on entry - and a hardware device is 'engaged' - a soft keyboard still appears when focus is set to the entry field. We would like the keyboard to stop appearing and we are aware that the 'Show on-screen keyboard' option (an icon that appears, and when pressed shows the switch) set to off gives us the right behaviour. How can we change this device setting from code? - rather than hiding the soft keyboard on focus like many other threads on here which causes the keyboard to glitch (on off really quickly).

Best Answer

Answers

  • TobyKTobyK GBMember ✭✭✭
  • TobyKTobyK GBMember ✭✭✭

    Ok, investigating the creation of a custom entry control - as http://stackoverflow.com/questions/38583516/xamarin-forms-custom-entry-renderer-that-hides-soft-keyboard seems to work.

  • TobyKTobyK GBMember ✭✭✭

    Here's my attempt at a custom renderer for the following: Create an entry field and a button, where the button toggles on/off to indicate when to show the soft keyboard on an android platform when focus is set to the entry field...

    So my custom renderer as follows:

    namespace Mobile.Controls
    {
        public class BarcodeEntry : Entry
        {
            private bool isKeyboardVisible;
    
            public static BindableProperty IsKeyboardVisibleProperty =
                BindableProperty.Create<BarcodeEntry, bool>(
                    x => x.IsKeyboardVisible, 
                    false, 
                    BindingMode.TwoWay, 
                    propertyChanged: HandleIsKeyboardVisiblePropertyChanged);
    
            public bool IsKeyboardVisible
            {
                get { return isKeyboardVisible; }
                set { isKeyboardVisible = value; }
            }
    
            public BarcodeEntry()
            {
                isKeyboardVisible = false;
            }
    
            private static void HandleIsKeyboardVisiblePropertyChanged(BindableObject bindable, bool oldValue, bool newValue)
            {
                var barcodeEntry = (BarcodeEntry)bindable;
                barcodeEntry.IsKeyboardVisible = newValue;
            }
        }
    }
    

    My View contains:

      <c:BarcodeEntry x:Name="entry" Text="{Binding Barcode}" IsKeyboardVisible="{Binding IsKeyboardVisible}" />
    

    And my custom renderer in the .Droid project:

    [assembly: ExportRenderer(typeof(BarcodeEntry), typeof(BarcodeEntryRenderer))]
    namespace Mobile.Droid
    {
        public class BarcodeEntryRenderer : EntryRenderer
        {
            protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
    
                if (e.PropertyName == "IsKeyboardVisible")
                {
                    var barcodeEntry = (BarcodeEntry)sender;
                    if (barcodeEntry != null)
                    {
                        if (Control != null)
                        {
                            Control.ShowSoftInputOnFocus = barcodeEntry.IsKeyboardVisible;
                        }
                    }
                }
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                base.OnElementChanged(e);
    
                if (e.NewElement != null)
                {
                    // Configure the native cotnrol and subscribe to event handlers
                    if (Control != null)
                    {
                        Control.ShowSoftInputOnFocus = (e.NewElement as BarcodeEntry).IsKeyboardVisible;
                    }
                }
                else if (e.OldElement != null)
                {
                    // Unsubscribe from event handlers and cleanup any reasources
                }
    
                if (base.Control != null)
                {
    
                } 
            }
        }
    }
    

    the problem I'm having is that when I set my viewModels IsKeyboardVisible property to true, its coming through as false via the renderer, and vice versa... Just wondering what I'm doing incorrectly.

  • TobyKTobyK GBMember ✭✭✭

    I've made some small modifications (simplified it slightly)

    namespace Mobile.Controls
    {
        public class BarcodeEntry : Entry
        {
            public static BindableProperty IsKeyboardVisibleProperty =
                BindableProperty.Create<BarcodeEntry, bool>(
                    x => x.IsKeyboardVisible, 
                    false, 
                    BindingMode.TwoWay, 
                    propertyChanged: HandleIsKeyboardVisiblePropertyChanged);
    
            public bool IsKeyboardVisible
            {
                get { return (bool)GetValue(IsKeyboardVisibleProperty); }
                set { SetValue(IsKeyboardVisibleProperty, value); }
            }
    
            public BarcodeEntry()
            {
            }
    
            private static void HandleIsKeyboardVisiblePropertyChanged(BindableObject bindable, bool oldValue, bool newValue)
            {
            }
        }
    }
    

    The renderer now looks like this:

    [assembly: ExportRenderer(typeof(BarcodeEntry), typeof(BarcodeEntryRenderer))]
    namespace Mobile.Droid
    {
        public class BarcodeEntryRenderer : EntryRenderer
        {
            protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
    
                if (e.PropertyName == "IsKeyboardVisible")
                {
                    var barcodeEntry = (BarcodeEntry)sender;
                    if (barcodeEntry != null)
                    {
                        if (Control != null)
                        {
                            Control.ShowSoftInputOnFocus = barcodeEntry.IsKeyboardVisible;
                        }
                    }
                }
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                base.OnElementChanged(e);
    
                if (e.NewElement != null)
                {
                    // Configure the native control and subscribe to event handlers
                    var barcodeEntry = e.NewElement as BarcodeEntry;
                    if (Control != null && barcodeEntry != null)
                    {
                        Control.ShowSoftInputOnFocus = barcodeEntry.IsKeyboardVisible;
                    }
                }
                else if (e.OldElement != null)
                {
                    // Unsubscribe from event handlers and cleanup any reasources
                }
    
                if (base.Control != null)
                {
    
                } 
            }
        }
    }
    

    Setting focus to the BarcodeEntry control manually, and it works fine - no keyboard appears when IsKeyboardVisible is false, keyboard appears if true. However, whenever I try to BarcodeEntryControl.Focus() in code, the keyboard still appears everytime? - If I then select some other control by hand and reselect the barcode entry by hand, the keyboard is not shown... weird, I can't figure it out....

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    @TobyK I have tried with this customrenderer for entry... I don't know if you can use it.
    There are two methods... Show and Hide...

    using Android.Text;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    using Eurospin.Droid;
    using Eurospin;
    using Android.Views.InputMethods;
    using Android.InputMethodServices;
    using Android.OS;
    using System;
    
    [assembly: ExportRenderer(typeof (MyEntry), typeof (ReadonlyEntryRenderer))]
    
    namespace Eurospin.Droid
    {
        public class ReadonlyEntryRenderer : EntryRenderer
        {
    
            private bool IsKeybordEnabled { get; set; }
            private bool IsFirst { get ; set; } = true; 
    
            // Override the OnElementChanged method so we can tweak this renderer post-initial setup
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                base.OnElementChanged(e);
                var oldEntry = e.OldElement as MyEntry;
                var newEntry = e.NewElement as MyEntry;
    
                if (newEntry != null)
                {
                    newEntry.ShowKeyboard += ShowKeyboardRequested;
                    newEntry.HideKeyboard += HideKeyboardRequested;
                }
                if (oldEntry != null)
                {
                    oldEntry.ShowKeyboard -= ShowKeyboardRequested;
                    oldEntry.HideKeyboard -= HideKeyboardRequested;
                }
    
                if (Control != null)
                {
                    Control.Click += (sender, evt) => {
                        new Handler().Post(delegate
                            {
                                if(Control != null){
                                    var imm = (InputMethodManager)Control.Context.GetSystemService(Android.Content.Context.InputMethodService);
                                    if(IsKeybordEnabled)
                                        imm.ShowSoftInput(Control, ShowFlags.Forced);
                                    else
                                        imm.HideSoftInputFromWindow(Control.WindowToken, 0);
                                }
    //                          Console.WriteLine(result);
                            });
                    };
    
                    Control.FocusChange += (sender, evt) => {
                        new Handler().Post(delegate
                            {
    //                          if(IsKeybordEnabled)
    //                              return;
                                if(Control != null){
                                    var imm = (InputMethodManager)Control.Context.GetSystemService(Android.Content.Context.InputMethodService);
                                    if(IsKeybordEnabled){
                                        System.Diagnostics.Debug.WriteLine ("show");
                                        imm.ShowSoftInput(Control, ShowFlags.Forced);
    //                                  IsFirst = false;
    //                                  IsKeybordEnabled = false;
                                    }
                                    else{
                                        System.Diagnostics.Debug.WriteLine ("hide");
    //                                  if(IsFirst)
                                            imm.HideSoftInputFromWindow(Control.WindowToken,0);
    //                                  else
    //                                      imm.HideSoftInputFromWindow(Control.WindowToken,HideSoftInputFlags.ImplicitOnly);
    //                                  //imm.HideSoftInputFromInputMethod (Control.WindowToken, 0);
                                    }
                                }
    //                          Console.WriteLine(result);
                            });
                    };
    
                }
    
            }
    
            private void ShowKeyboardRequested(object sender, EventArgs e)
            {
                IsKeybordEnabled = true;
                //Control.RequestFocus ();
    //          var imm = (InputMethodManager)Android.App.Application.Context.GetSystemService(Android.Content.Context.InputMethodService);
    //          imm.ToggleSoftInput (ShowFlags.Forced,HideSoftInputFlags.ImplicitOnly);
            }
    
            private void HideKeyboardRequested(object sender, EventArgs e){
    
                IsKeybordEnabled = false;
            }
    
        }
    } 
    
  • TobyKTobyK GBMember ✭✭✭

    @AlessandroCaliaro I've combined them both in my testing platform. I'm seeing what I'm expecting to see, so that's good! I will transfer it to the main app and test it some more tomorrow, but thank you for your help!

  • TobyKTobyK GBMember ✭✭✭

    Here's my attempt at a custom renderer for the following: Create an entry field and a button, where the button toggles on/off to indicate when to show the soft keyboard on an android platform when focus is set to the entry field...

    So my custom renderer as follows:

    namespace Mobile.Controls
    {
        public class BarcodeEntry : Entry
        {
            private bool isKeyboardVisible;
    
            public static BindableProperty IsKeyboardVisibleProperty =
                BindableProperty.Create<BarcodeEntry, bool>(
                    x => x.IsKeyboardVisible, 
                    false, 
                    BindingMode.TwoWay, 
                    propertyChanged: HandleIsKeyboardVisiblePropertyChanged);
    
            public bool IsKeyboardVisible
            {
                get { return isKeyboardVisible; }
                set { isKeyboardVisible = value; }
            }
    
            public BarcodeEntry()
            {
                isKeyboardVisible = false;
            }
    
            private static void HandleIsKeyboardVisiblePropertyChanged(BindableObject bindable, bool oldValue, bool newValue)
            {
                var barcodeEntry = (BarcodeEntry)bindable;
                barcodeEntry.IsKeyboardVisible = newValue;
            }
        }
    }
    
  • TobyKTobyK GBMember ✭✭✭

    Here's my attempt at a custom renderer for the following: Create an entry field and a button, where the button toggles on/off to indicate when to show the soft keyboard on an android platform when focus is set to the entry field...

    So my custom renderer as follows:

    namespace Mobile.Controls
    {
        public class BarcodeEntry : Entry
        {
            private bool isKeyboardVisible;
    
            public static BindableProperty IsKeyboardVisibleProperty =
                BindableProperty.Create<BarcodeEntry, bool>(
                    x => x.IsKeyboardVisible, 
                    false, 
                    BindingMode.TwoWay, 
                    propertyChanged: HandleIsKeyboardVisiblePropertyChanged);
    
            public bool IsKeyboardVisible
            {
                get { return isKeyboardVisible; }
                set { isKeyboardVisible = value; }
            }
    
            public BarcodeEntry()
            {
                isKeyboardVisible = false;
            }
    
            private static void HandleIsKeyboardVisiblePropertyChanged(BindableObject bindable, bool oldValue, bool newValue)
            {
                var barcodeEntry = (BarcodeEntry)bindable;
                barcodeEntry.IsKeyboardVisible = newValue;
            }
        }
    }
    
  • UweReisewitzUweReisewitz DEMember ✭✭

    Hi,
    this is quiet an old thread but in case someone is searching for a solution:
    I have created a sample with full control over the virtual keyboard (and support for the cursor) and posted it on GutHub:
    https://github.com/UweReisewitz/XamarinAndroidEntry

Sign In or Register to comment.