16

After much searching, I worked out a way to hide the keyboard on a button press in Xamarin Forms for iOS. So it's shared below.

If anyone can improve it, or share a solution for the Android side, that would be great.

ag93
  • 343
  • 4
  • 17
BillF
  • 1,034
  • 3
  • 13
  • 28

13 Answers13

25

I found this useful:

https://forums.xamarin.com/discussion/comment/172077#Comment_172077

Interface:

public interface IKeyboardHelper
{
    void HideKeyboard();
}

iOS:

public class iOSKeyboardHelper : IKeyboardHelper
{
    public void HideKeyboard()
    {
        UIApplication.SharedApplication.KeyWindow.EndEditing(true);
    }
}

Droid:

public class DroidKeyboardHelper : IKeyboardHelper
{
    public void HideKeyboard()
    {
        var context = Forms.Context;
        var inputMethodManager = context.GetSystemService(Context.InputMethodService) as InputMethodManager;
        if (inputMethodManager != null && context is Activity)
        {
            var activity = context as Activity;
            var token = activity.CurrentFocus?.WindowToken;
            inputMethodManager.HideSoftInputFromWindow(token, HideSoftInputFlags.None);

            activity.Window.DecorView.ClearFocus();
        }
    }
}

Usage in Xamarin Forms:

DependencyService.Get<IKeyboardHelper>().HideKeyboard();
F. Badili
  • 261
  • 3
  • 3
12

If the removing focus method is not working for you (and it wasn't working for me) after a lot of searching I realized an easy way to force the keyboard to dismiss.

FindViewById<EditText>(Resource.Id.edittextname).Enabled = false;
FindViewById<EditText>(Resource.Id.edittextname).Enabled = true;

That's it. Just disable and enable it and it will close the keyboard.

Alex
  • 552
  • 3
  • 15
9
 view.Unfocus();

That's it.

Some people report this not working, but it's worked like gangbusters for me.

Le Mot Juiced
  • 3,761
  • 1
  • 26
  • 46
7

Here's an updated version of F. Badili's solution based on a deprecating change in Xamarin Forms 2.5. The only difference is how the Context is accessed in the Android class.

In the Xamarin Forms project:

public interface IKeyboardHelper
{
    void HideKeyboard();
}   

In the iOS project:

using System;
using Xamarin.Forms;
using ProjectName;
using ProjectName.iOS;
using UIKit;

[assembly: Dependency(typeof(iOSKeyboardHelper))]
namespace ProjectName.iOS
{
    public class iOSKeyboardHelper : IKeyboardHelper
    {
        public void HideKeyboard()
        {
            UIApplication.SharedApplication.KeyWindow.EndEditing(true);
        }
    }
}

In the Droid Project:

using System;
using Xamarin.Forms;
using ProjectName;
using ProjectName.Droid;
using Xamarin.Forms.Platform.Android;
using Android.Views.InputMethods;
using Android.App;
using Android.Content;

[assembly: Xamarin.Forms.Dependency(typeof(DroidKeyboardHelper))] 
namespace ProjectName.Droid
{
    public class DroidKeyboardHelper : IKeyboardHelper
    {
        public void HideKeyboard()
        {
            var context = Android.App.Application.Context;
            var inputMethodManager = context.GetSystemService(Context.InputMethodService) as InputMethodManager;
            if (inputMethodManager != null && context is Activity)
            {
                var activity = context as Activity;
                var token = activity.CurrentFocus?.WindowToken;
                inputMethodManager.HideSoftInputFromWindow(token, HideSoftInputFlags.None);

                activity.Window.DecorView.ClearFocus();
            }
        }
    }
}

In Xamarin Forms page:

DependencyService.Get<IKeyboardHelper>().HideKeyboard();
Kenan Casey
  • 71
  • 1
  • 4
  • **Android.App.Application.Context** didn't work for me. Only the **Forms.Context**. Because *context is Activity* getting false – D.madushanka Feb 19 '21 at 12:32
  • For me, neither Forms.Context nor Application.Context worked. What did work was to use Plugin.CurrentActivity, with var context = CrossCurrentActivity.Current.Activity; – BillF Mar 18 '21 at 08:34
5

This is my solution to hide the virtual keyboard for the Android side.

I coded a IKeyboardInteractions interface which has a HideKeyboard() method. Then I declare a KeyboardInteractions class in MyProject.Droid which implements IKeyboardInteractions :

Common code :

public interface IKeyboardInteractions {
    void HideKeyboard();
}

MyProject.Droid code:

[assembly: Dependency (typeof (KeyboardInteractions))] namespace MyProject.Droid
{
    public class KeyboardInteractions : IKeyboardInteractions
    {
        public void HideKeyboard()
        {
            var inputMethodManager = Xamarin.Forms.Forms.Context.GetSystemService(Context.InputMethodService) as InputMethodManager;
            if (inputMethodManager != null && Xamarin.Forms.Forms.Context is Activity)
            {
                var activity = Xamarin.Forms.Forms.Context as Activity;
                var token = activity.CurrentFocus == null ? null : activity.CurrentFocus.WindowToken;
                inputMethodManager.HideSoftInputFromWindow(token, 0);
            }
        }
    }
}

Consuming method:

IKeyboardInteractions keyboardInteractions = DependencyService.Get<IKeyboardInteractions>();
keyboardInteractions.HideKeyboard ();
Gustavo Morales
  • 2,614
  • 9
  • 29
  • 37
Nicolas Bodin
  • 1,431
  • 1
  • 20
  • 25
  • Thanks so much Nicholas. Will be trying it out down the track. – BillF May 31 '16 at 23:41
  • 1
    `Xamarin.Forms.Forms.Context` is deprecated since XF 2.5. `Android.App.Application.Context` seems to be the wrong context. Which one do you use now? – testing Apr 23 '18 at 11:28
  • 1
    @testing me too. **Android.App.Application.Context** didn't work for me. Only the **Forms.Context** working – D.madushanka Feb 22 '21 at 06:56
  • For me, neither Forms.Context nor Application.Context worked. What did work was to use Plugin.CurrentActivity, with var context = CrossCurrentActivity.Current.Activity; – BillF Mar 18 '21 at 08:30
5

I couldn't get F. Badili's solution for Android to work even with Kenan Casey's update on it. Further googling took me to Dave's Tech Blog regarding the deprecation of Xamarin.Forms.Forms.Context. It says Android.App.Application.Context is not and can't be converted to Activty (at least in my case, refer to the blog post's comments for the explanation).

In the Droid Project:

[assembly: Xamarin.Forms.Dependency(typeof(DroidKeyboardHelper))] 
namespace ProjectName.Droid{
    public class DroidKeyboardHelper : IKeyboardHelper {
        static Context _context;

        public static void Init(Context context) => _context = context;

        public void HideKeyboard(){
            var inputMethodManager = _context.GetSystemService(Context.InputMethodService) as InputMethodManager;
            if (inputMethodManager != null && _context is Activity) {
                var activity = _context as Activity;
                var token = activity.CurrentFocus?.WindowToken;
                inputMethodManager.HideSoftInputFromWindow(token, HideSoftInputFlags.None);

                activity.Window.DecorView.ClearFocus();
            }
        }
    }
}

In the Droid MainActivity.cs:

protected override void OnCreate(Bundle savedInstanceState){
    base.OnCreate(savedInstanceState);
    ...
    KeyboardHelper.Init(this);
    ...
    LoadApplication(new App());
}

NOTE:

This will only work if your app only runs on a single activity. If in any case your app has multiple activity, please refer to Dave's Tech Blog for a proper implementation for your case.

Julio Motol
  • 763
  • 5
  • 22
3

You can give a name to the entry fields. For instance Entryfield1 and EntryField2 are the entries that showed the keyboard. Then override the Page Events with OnDisappearing like below:

protected override void OnDisappearing()
{
    Entryfield1.Unfocus();
    EntryField2.Unfocus();
    base.OnDisappearing();
}
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Rahoo
  • 31
  • 3
2

In the shared/PCL project, add:

using System;
using Xamarin.Forms;

namespace MyApp.Views
{
    public class ButtonKeyboardHiding : Button {}
}

Use this class in place of Button in your forms.

In the iOS project, add:

using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using Foundation;
using UIKit;
using MyApp.Views;
using MyApp.iOS;

[assembly: ExportRenderer ( typeof (ButtonKeyboardHiding), typeof (ButtonKeyboardHidingRenderer ) ) ]

namespace MyApp.iOS
{
    public class ButtonKeyboardHidingRenderer : ButtonRenderer
    {
        protected override void OnElementChanged ( ElementChangedEventArgs<Button> e )
        {
            base.OnElementChanged  (e );

            if ( Control != null ) 
            {   
                Control.TouchUpInside += ( sender, el ) =>
                {
                    UIView ctl = Control;
                    while ( true )
                    {
                        ctl = ctl.Superview;
                        if ( ctl.Description.Contains ( "UIView" ) )
                            break;
                    }
                    ctl.EndEditing ( true );
                };
            }
        }
    }
}
BillF
  • 1,034
  • 3
  • 13
  • 28
  • Seems ridiculous that you can't iterate through the views on a ListView. Thanks, for this idea. – Sandy Chapman Jun 11 '15 at 22:46
  • I tried, but it's not working. And when I click the button a 2nd time (after keyboard closes), I'm getting an exception. – jbyrd Aug 14 '17 at 16:50
1

Forms9Patch has a good working implementation.

So just use the whole library (https://github.com/baskren/Forms9Patch) or use their code from the Github repo (KeyboardService.cs).

Using it is quite easy then:

Forms9Patch.KeyboardService.Hide();

Available for Android, iOS and UWP.

Gabriel Weidmann
  • 756
  • 12
  • 16
0

Simple solution in code behind Xamarin Forms 4.8. Subscribe to TextChanged event, i.e. Editor or Entry, then check the key in the code behind. As Le Mot Juiced answered, UnFocused() will close the keyboard. My example closes the keyboard after the enter key is pressed, but you can apply another key to the condition.

XAML

 <Editor TextChanged="Input_TextChanged"></Editor>

Code behind

private void Input_TextChanged(object sender, TextChangedEventArgs e)
    {
        char key = string.IsNullOrEmpty(e.NewTextValue) ? ' ' : e.NewTextValue.Last();
        if (key == '\n')
        {
            var s = (Editor)sender;
            s.Text = e.OldTextValue ?? string.Empty;
            s.Unfocus();
        }
    }
chri3g91
  • 1,196
  • 14
  • 16
  • Well focus is lost, but it doesn't seem to make keyboard disappear? (I use this on a simple Entry element and adapted). – gfmoore May 19 '22 at 17:11
0

I had an issue where the keyboard was not closing for a TapGestureRecognizer for Android. To fix this I had to replace the Span with a button. Commented out code below is what was not working for me in terms of closing the keyboard. Keyboard was automatically closed on clicking the button in Android.

               <Button VerticalOptions="Center" Text="Login" Command="{Binding LoginCommand}"/>

            <!--
            <StackLayout Grid.Row="2" Padding="20">
                <Label HorizontalOptions="Center">
                    <Label.FormattedText>
                        <FormattedString>
                            <Span Text="Login" TextColor="Blue">
                                <Span.GestureRecognizers>
                                    <TapGestureRecognizer Command="{Binding LoginCommand}"/>
                                </Span.GestureRecognizers>
                            </Span>
                        </FormattedString>
                    </Label.FormattedText>
                </Label>
            </StackLayout>
            -->
0

UnFocus() worked for me, with some caveats.

I had two pages: EditPage had an Entry control, that, when focused, displayed the keyboard. ListPage had no Entry field. When EditPage was displayed, and the Entry focused, the keyboard was displayed. If I now navigated to ListPage, the keyboard remained displayed.

To resolve, I tried these:

1.) In ListPage.OnAppearing() I added a call to Unfocus().

Silly, as there is nothing focused at this point, but if this is the way to hide the keyboard, was worth a try. Also, this page should be responsible for showing or hideing the keyboard, no matter where we caome from.

Didn't work.

2.) In EditPage.OnDisappearing(), I added Unfocus() like so:

protected override void OnDisappearing()
{
    Unfocus();
    base.OnDisappearing();
}

This works.

balintn
  • 988
  • 1
  • 9
  • 19
0

The best way i have found, API > 30 is to create an instance of MainActivity as a static resource:

internal static MainActivity Instance { get; private set; }

And then to reference it and hide the InsetsController that handles media entry:

MainActivity.Instance.Window.InsetsController.Hide(WindowInsets.Type.Ime());

This can be done using Dependency Service if using multi platform:

 IKeyboardInteractions kbi = DependencyService.Get<IKeyboardInteractions>();
            
 kbi.HideKeyboard();

The reverse can be done to show the keyboard at any time:

MainActivity.Instance.Window.InsetsController.Show(WindowInsets.Type.Ime());
gzuz90
  • 1
  • 1