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.
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.
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();
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.
view.Unfocus();
That's it.
Some people report this not working, but it's worked like gangbusters for me.
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();
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 ();
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.
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();
}
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 );
};
}
}
}
}
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.
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();
}
}
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>
-->
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.
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());