Field "HandleKeyboardOnFocus" always null

MojackMojack Member ✭✭
edited March 18 in Xamarin.Forms

Hey guys,

I have an app where you can scan barcodes.
If a view is loading, I set the focus programmatically on the searchbar ( MySearchBar.Focus() ).
With the following code I prevent the keyboard to popup:

    class HideSearchBarKeyboard : SearchBarRenderer {
        public HideSearchBarKeyboard(Context context) : base(context) {
        }
        protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e) {
            base.OnElementChanged(e);
            if (e.OldElement == null) {
                var field = this.GetType().GetField("HandleKeyboardOnFocus", BindingFlags.Instance | BindingFlags.NonPublic);
                field.SetValue(this, false);
            }
        }
    }

Today I upgraded Xamarin.Forms to version 3.6 and after that the "field" property is always null.

I checked the github page and found some requests like the pull request "4248" (can't post links, sorry)

But I have absolutely no clue, how I can now hide the keyboard when I focus the searchbar.

So the previews behavior was:

  • Open some view = keyboard hidden
  • MySearchBar.Focus() = keyboard hidden
  • User clicked on searchbar = keyboard shown

Can someone guide me to the right direction?

Tagged:

Answers

  • JohnHardmanJohnHardman GBUniversity mod
    edited March 18

    @Mojack

    I think you probably want to look at https://github.com/xamarin/Xamarin.Forms/pull/4384 (4384, rather than 4248)

    See if the description there gives you a point in the right direction.

    It appears that HandleKeyboardOnFocus is history.

  • MojackMojack Member ✭✭

    So, I added "Context.HideKeyboard(this)", but that didn't work.
    I also tried to add this on "OnFocusChangeRequested" and "OnFocusChanged".

        class HideSearchBarKeyboard : SearchBarRenderer {
            public HideSearchBarKeyboard(Context context) : base(context) {
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e) {
                base.OnElementChanged(e);
    
                if (e.OldElement == null) {
                    var field = this.GetType().GetField("HandleKeyboardOnFocus", BindingFlags.Instance | BindingFlags.NonPublic);
                    //field.SetValue(this, false);
                    Context.HideKeyboard(this);
                }
            }
    
            protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e) {
                base.OnFocusChangeRequested(sender, e);
                Context.HideKeyboard(this);
            }
    
            protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, Rect previouslyFocusedRect) {
                base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect);
                Context.HideKeyboard(this);
            }
        }
    
  • MojackMojack Member ✭✭

    @EZHart @ShaneNeuville
    I heard you were involved in these changes?
    Can you show me the right way to hide the keyboard?

  • ShaneNeuvilleShaneNeuville USUniversity ✭✭

    if you don't call base.OnFocusChangeRequested(sender, e); on the override that should cause the keyboard not to show up

    the code that shows the keyboard posts it to the UI Thread so it happens after your call to Context.HideKeyboard

            internal static void PostShowKeyboard(this AView view)
            {
                void ShowKeyboard()
                {
                    // Since we're posting this on the queue, it's possible something else will have disposed of the view
                    // by the time the looper is running this, so we have to verify that the view is still usable
                    if (view.IsDisposed())
                    {
                        return;
                    }
    
                    view.ShowKeyboard();
                };
    
                Device.BeginInvokeOnMainThread(ShowKeyboard);
            }
    
  • MojackMojack Member ✭✭

    @ShaneNeuville thanks for the reply!

    I can't wrap my head around it.
    So basically I want no keyboard on the same override so I ended up like this:

    [assembly: ExportRenderer(typeof(SearchBar), typeof(HideSearchBarKeyboard))]
    namespace Warehouse.Droid.Internal {
        public class HideSearchBarKeyboard : SearchBarRenderer {
            public HideSearchBarKeyboard(Context context) : base(context) { }
    
            protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e) {
                base.OnElementChanged(e);
    
                if (e.OldElement == null) {
                    Context.HideKeyboard(this);
                    base.OnFocusChangeRequested(this, new VisualElement.FocusRequestArgs { Focus = true });
                }
            }
        }
    }
    

    IMHO there is nothing wrong. If the "OldElement" is null, don't show the keyboard and focus the searchbar.
    If not (when the user tapped on the searchbar), do nothing (show the keyboard regularly)

    My problem is, that the keyboard still shows up. What do I do wrong?

  • MojackMojack Member ✭✭

    Push

  • fxxmfxxm Member

    Try replacing this:

             protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e) 
        {
                 base.OnElementChanged(e);
                 if (e.OldElement == null) {
                     var field = this.GetType().GetField("HandleKeyboardOnFocus", BindingFlags.Instance | BindingFlags.NonPublic);
                     field.SetValue(this, false);
              }
    

    with:

        protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e)
            {
                Context.HideKeyboard(this);
            }
    
  • PopowichPopowich Member
    edited May 17

    For myself, I decided this way. Now the field remains in the input focus (set by software), but the keyboard does not appear by redefining OnFocusChangeRequested in this way. Otherwise, as suggested above, the field remained without input focus

        protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e)
        {
            if (Control == null)
                return;
    
            e.Result = true;
    
            if (e.Focus)
            {
                Device.BeginInvokeOnMainThread(() => {
                    if (Control == null || Control.Handle == IntPtr.Zero)
                        return;
    
                    if (Control is IPopupTrigger popupElement)
                        popupElement.ShowPopupOnFocus = true;
    
                    Control?.RequestFocus();
                });
            }
            else
            {
                Control.ClearFocus();
            }
        }
    
Sign In or Register to comment.