Forum Xamarin.Forms

Prevent Entry soft keyboard from showing on Android

akevanakevan CAMember ✭✭
edited February 2015 in Xamarin.Forms

I am programmatically entering text into a bunch of Entry controls in a ContentPage. I don't want the keyboard to show since the user isn't supposed to type into them - the text comes from a different async service. But I do want the blinking cursor to show as visual feedback.

This is a common problem in Android land with everyone stating the same solutions (here and here).

So I have a custom renderer for the Entry control, which looks like this for Android:

[assembly: ExportRenderer (typeof (MyEntry), typeof (MyEntryRenderer_Android))]
public class MyEntryRenderer_Android: EntryRenderer
{   
    protected override void OnElementChanged (ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged (e);
        if (e.OldElement == null) {
            //  **** this doesn't work
            InputMethodManager imm = (InputMethodManager)Context.GetSystemService(global::Android.Content.Context.InputMethodService);
            imm.HideSoftInputFromWindow(Control.WindowToken, HideSoftInputFlags.None);
        }
    }

    protected override void OnAttachedToWindow()
    {
        //  **** this doesn't work either
        InputMethodManager imm = (InputMethodManager)Context.GetSystemService(global::Android.Content.Context.InputMethodService);
        imm.HideSoftInputFromWindow(Control.WindowToken, HideSoftInputFlags.None);
        base.OnAttachedToWindow();
    }

    public override bool OnInterceptTouchEvent(MotionEvent e)
    {
        // **** this does work
        Control.RequestFocus();
        if (UIControl.Instance.VoiceInputEnabled)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

You can see my attempts at preventing the keyboard in OnElementChangedand OnAttachedToWindow. They don't work, it still pops up when I programmatically set focus to the control. However, if the user clicks on the entry, that OnInterceptTouchEvent override is called and that does prevent the keyboard from showing.

BTW I have also tried this in my MainActivity.cs for Android:

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    this.Window.SetSoftInputMode(SoftInput.StateAlwaysHidden);

    //...
}

Still no dice. How can prevent it from showing?

Posts

  • fernandopfernandop USMember ✭✭

    Hi, did you solve this? I created a workaround to fix this, it looks bad but it is the only way I found to accomplish that. Please, tell me if you found a "good" solution or if you want to see my solution, Xamarin support thinks it is a bug but still didnt fix it.

  • NarayanaSwamyNarayanaSwamy INMember
    edited July 2015

    Hi @akevan

    this.Window.SetSoftInputMode(SoftInput.StateAlwaysHidden);

    this line works fine for me.

  • akevanakevan CAMember ✭✭
    edited July 2015

    That works for Xamarin.Android, but not for an Entry Renderer in Xamarin Forms. It's confirmed that the functionality doesn't exist - https://bugzilla.xamarin.com/show_bug.cgi?id=27613.

    In the meantime, I've written a custom renderer for my Entry control w/ a bindable text field.

    Forms Code:

    namespace Whatever
    {
        public class MyEntry : View
        {
            public string Placeholder { get; set; }
    
            // Bindable Text Property
            public static readonly BindableProperty TextProperty = BindableProperty.Create<SpeechEntry, string> (p => p.Text, default(string)); 
            public string Text 
            { 
                get { return (string)GetValue(TextProperty); }
                set { SetValue (TextProperty, value); }
            }
        }
    }
    

    Android Renderer:
    (it was doing funky recursive setting of text w/ two way binding, the _setFromTextInput flag is to deal with that)

    [assembly:ExportRenderer(typeof(MyEntryEntry), typeof(MyEntryRenderer))]
    namespace Whatever.Android
    {
        public class MyEntryRenderer : ViewRenderer<MyEntry, EditText> 
        {
            private bool _setFromTextInput = false;
    
            protected override void OnElementChanged (ElementChangedEventArgs<MyEntry> e){
                base.OnElementChanged (e);
                if (e.OldElement != null || this.Element == null)
                    return;
    
                var editText = new EditText (Forms.Context) {
                    Text = Element.Text,
                    Hint = Element.Placeholder,
                    TextSize = 15
                };
    
                editText.TextChanged += (object sender, global::Android.Text.TextChangedEventArgs te) => {
                    _setFromTextInput = true;
                    ((IElementController)Element).SetValueFromRenderer (MyEntry.TextProperty, Control.Text);
                };
    
                SetNativeControl (editText);
    
                InputMethodManager imm = (InputMethodManager)Context.GetSystemService(global::Android.Content.Context.InputMethodService);
                imm.HideSoftInputFromWindow(Control.ApplicationWindowToken, HideSoftInputFlags.None);
            }        
    
            protected override void OnElementPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged (sender, e);
    
                if (Control == null || Element == null)
                    return;
    
                if (e.PropertyName == MyEntry.TextProperty.PropertyName) 
                {
                    if (!_setFromTextInput) 
                    {
                        Control.Text = Element.Text;
                    }
                    _setFromTextInput = false;
                }
            }    
        }
    }
    
  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    I have used this

    public class ReadonlyEntryRenderer : EntryRenderer
    {
        // Override the OnElementChanged method so we can tweak this renderer post-initial setup
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);
    
            if (Control != null)
            {
                Control.Click += (sender, evt) => {
                    new Handler().Post(delegate
                        {
                            var imm = (InputMethodManager)Control.Context.GetSystemService(Android.Content.Context.InputMethodService);
                            var result = imm.HideSoftInputFromWindow(Control.WindowToken, 0);
    
                            Console.WriteLine(result);
                        });
                };
    
                Control.FocusChange += (sender, evt) => {
                    new Handler().Post(delegate
                        {
                            var imm = (InputMethodManager)Control.Context.GetSystemService(Android.Content.Context.InputMethodService);
                            var result = imm.HideSoftInputFromWindow(Control.WindowToken, 0);
    
                            Console.WriteLine(result);
                        });
                };
    
            }
        }
    }
    
  • dinobdinob USUniversity ✭✭✭

    None of these prevent keyboard from showing. They show soft keyboard, then hide it which is even worse.

  • dinobdinob USUniversity ✭✭✭

    @AlessandroCaliaro said:
    I have used this

    public class ReadonlyEntryRenderer : EntryRenderer
    {
    // Override the OnElementChanged method so we can tweak this renderer post-initial setup
    protected override void OnElementChanged(ElementChangedEventArgs e)
    {
    base.OnElementChanged(e);

          if (Control != null)
          {
              Control.Click += (sender, evt) => {
                  new Handler().Post(delegate
                      {
                          var imm = (InputMethodManager)Control.Context.GetSystemService(Android.Content.Context.InputMethodService);
                          var result = imm.HideSoftInputFromWindow(Control.WindowToken, 0);
    
                          Console.WriteLine(result);
                      });
              };
    
              Control.FocusChange += (sender, evt) => {
                  new Handler().Post(delegate
                      {
                          var imm = (InputMethodManager)Control.Context.GetSystemService(Android.Content.Context.InputMethodService);
                          var result = imm.HideSoftInputFromWindow(Control.WindowToken, 0);
    
                          Console.WriteLine(result);
                      });
              };
    
          }
      }
    

    }

    why all code duplication?

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    I think it could be written better

  • dinobdinob USUniversity ✭✭✭
    edited November 2018

    @AlessandroCaliaro said:
    I think it could be written better

    o, ok, I just thought maybe there is some code missing. It is also never detaching events, probably memory leak?
    However, I still dont understand how is it suppose to prevent keyboard from showing. To me, all it does is hide it after the fact that it has been shown on both Click and FocusChange events. But I guess, it is good enough for your requirement.
    Thanks anyways, I need to prevent soft keyboard from showing, not to hide it after it has been shown

  • NMackayNMackay GBInsider, University admin

    @dinob said:

    @AlessandroCaliaro said:
    I think it could be written better

    o, ok, I just thought maybe there is some code missing

    4 lines...may less with resharper. Post some refactored code.

  • dinobdinob USUniversity ✭✭✭

    @NarayanaSwamy said:
    Hi @akevan

    this.Window.SetSoftInputMode(SoftInput.StateAlwaysHidden);

    this line works fine for me.

    This hides keyboard entirely on Window. What if you have 2 Entries, one should have keyboard disabled, the other one should have it enabled. How to hide it on only that one particular Entry?

  • truXtontruXton Member ✭✭

    I think i found a sort of hack... but for me is ok...

    1. Create custom entry renderer in android and...
      Control.ShowSoftInputOnFocus = false;
      Control.SetCursorVisible(false);
      Control.InputType = InputTypes.Null;

    2. This is not enough, because entry.Focus() show keyboard... I suggest you replace entry.Focus whit this: " entry.CursorPosition = entry.CursorPosition == 0 ? 1 : 0;"

Sign In or Register to comment.