How can I programmatically close or hide the Android soft keyboard?
I have an EditText and a Button in my Android layout. After entering text in the EditText and clicking the Button, I want to hide the virtual keyboard when the user touches outside of it. Can someone provide a simple code example demonstrating how to achieve this functionality?
To programmatically hide the Android soft keyboard, you can use the InputMethodManager service combined with methods to detect touch events outside your EditText. The most common approach involves calling hideSoftInputFromWindow() with the EditText’s window token and overriding touch events to detect when users tap outside the input field.
Contents
- Basic Keyboard Hiding Methods
- Hiding Keyboard on Button Click
- Hiding Keyboard on Touch Outside
- Alternative Approaches
- Complete Example Implementation
Basic Keyboard Hiding Methods
The fundamental approach to hiding the soft keyboard involves using Android’s InputMethodManager service. This service provides system-level access to input methods, including the soft keyboard.
// Method to hide keyboard from any context
public static void hideKeyboard(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
This method works by:
- Getting the InputSystemService from the current context
- Calling
hideSoftInputFromWindow()with the view’s window token - The second parameter (0) represents flags, which can be customized for different behaviors
For hiding the keyboard specifically from an EditText, you can use:
// Hide keyboard from EditText
EditText editText = findViewById(R.id.editText);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
Hiding Keyboard on Button Click
To hide the keyboard when a button is clicked, you can set an OnClickListener on your Button that calls the hide method:
Button submitButton = findViewById(R.id.submitButton);
submitButton.setOnClickListener(v -> {
// Hide keyboard when button is clicked
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(currentView.getWindowToken(), 0);
// Optional: Clear focus from EditText
EditText editText = findViewById(R.id.editText);
editText.clearFocus();
});
A more comprehensive approach that handles both button clicks and touch events:
public class MainActivity extends AppCompatActivity {
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = findViewById(R.id.editText);
Button submitButton = findViewById(R.id.submitButton);
// Hide keyboard on button click
submitButton.setOnClickListener(v -> hideKeyboard());
// Set up touch listener for the entire layout
findViewById(R.id.rootLayout).setOnTouchListener(this::onRootLayoutTouch);
}
private void hideKeyboard() {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
editText.clearFocus();
}
private boolean onRootLayoutTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (isTouchOutsideEditText(event)) {
hideKeyboard();
return true;
}
}
return false;
}
private boolean isTouchOutsideEditText(MotionEvent event) {
int[] editTextLocation = new int[2];
editText.getLocationOnScreen(editTextLocation);
float touchX = event.getRawX();
float touchY = event.getRawY();
return touchX < editTextLocation[0] ||
touchX > editTextLocation[0] + editText.getWidth() ||
touchY < editTextLocation[1] ||
touchY > editTextLocation[1] + editText.getHeight();
}
}
Hiding Keyboard on Touch Outside
The most robust solution involves overriding the activity’s dispatchTouchEvent method to detect touch events anywhere on the screen and hide the keyboard when the user taps outside the EditText:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (v instanceof EditText) {
Rect outRect = new Rect();
v.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
// User touched outside the EditText, hide keyboard
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(event);
}
This approach works by:
- Checking if the current focused view is an EditText
- Getting the global visible rectangle of the EditText
- Comparing the touch coordinates with the EditText boundaries
- Hiding the keyboard if the touch is outside the EditText
For Kotlin implementation:
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (ev?.action == MotionEvent.ACTION_DOWN) {
currentFocus?.let { view ->
if (view is EditText) {
val rect = Rect()
view.getGlobalVisibleRect(rect)
if (!rect.contains(ev.rawX.toInt(), ev.rawY.toInt())) {
view.clearFocus()
getSystemService(Context.INPUT_METHOD_SERVICE)?.let { imm ->
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
}
}
}
}
return super.dispatchTouchEvent(ev)
}
Alternative Approaches
Using Window Soft Input Mode
You can configure the keyboard behavior in your AndroidManifest.xml:
<activity
android:name=".MainActivity"
android:windowSoftInputMode="stateHidden|adjustPan" />
Common values for windowSoftInputMode:
stateHidden: Keyboard is hidden when the activity startsstateAlwaysHidden: Keyboard is always hiddenadjustPan: Content pans when keyboard appearsadjustResize: Window resizes when keyboard appears
Using ViewTreeObserver
Another approach is to use the ViewTreeObserver to detect layout changes:
editText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
editText.getWindowVisibleDisplayFrame(r);
int screenHeight = getWindow().getDecorView().getRootView().getHeight();
int keypadHeight = screenHeight - r.bottom;
if (keypadHeight > screenHeight * 0.15) { // 15% threshold
// Keyboard is visible
} else {
// Keyboard is hidden
}
}
});
Using Espresso for Testing
If you need to hide keyboard in UI tests:
// Using Espresso
onView(withId(R.id.editText)).perform(closeSoftKeyboard());
Complete Example Implementation
Here’s a complete, practical implementation combining multiple approaches:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private EditText nameEditText, emailEditText;
private Button submitButton;
private ScrollView rootLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize views
nameEditText = findViewById(R.id.nameEditText);
emailEditText = findViewById(R.id.emailEditText);
submitButton = findViewById(R.id.submitButton);
rootLayout = findViewById(R.id.rootLayout);
// Set up listeners
setupClickListeners();
}
private void setupClickListeners() {
// Hide keyboard on button click
submitButton.setOnClickListener(v -> {
hideKeyboard();
handleSubmit();
});
// Hide keyboard when clicking outside EditText fields
rootLayout.setOnTouchListener(this::onRootLayoutTouch);
}
private void hideKeyboard() {
hideKeyboard(nameEditText);
hideKeyboard(emailEditText);
}
private void hideKeyboard(View view) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
view.clearFocus();
}
private boolean onRootLayoutTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (isTouchOutsideEditTexts(event)) {
hideKeyboard();
return true;
}
}
return false;
}
private boolean isTouchOutsideEditTexts(MotionEvent event) {
int[] nameLocation = new int[2];
int[] emailLocation = new int[2];
nameEditText.getLocationOnScreen(nameLocation);
emailEditText.getLocationOnScreen(emailLocation);
float touchX = event.getRawX();
float touchY = event.getRawY();
// Check if touch is outside both EditText fields
boolean outsideName = touchX < nameLocation[0] ||
touchX > nameLocation[0] + nameEditText.getWidth() ||
touchY < nameLocation[1] ||
touchY > nameLocation[1] + nameEditText.getHeight();
boolean outsideEmail = touchX < emailLocation[0] ||
touchX > emailLocation[0] + emailEditText.getWidth() ||
touchY < emailLocation[1] ||
touchY > emailLocation[1] + emailEditText.getHeight();
return outsideName && outsideEmail;
}
private void handleSubmit() {
String name = nameEditText.getText().toString().trim();
String email = emailEditText.getText().toString().trim();
if (name.isEmpty() || email.isEmpty()) {
Toast.makeText(this, "Please fill all fields", Toast.LENGTH_SHORT).show();
return;
}
// Process form submission
Toast.makeText(this, "Form submitted successfully!", Toast.LENGTH_SHORT).show();
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (v instanceof EditText) {
Rect outRect = new Rect();
v.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
v.clearFocus();
hideKeyboard(v);
}
}
}
return super.dispatchTouchEvent(event);
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/nameEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter your name"
android:inputType="textPersonName"/>
<EditText
android:id="@+id/emailEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="Enter your email"
android:inputType="textEmailAddress"/>
<Button
android:id="@+id/submitButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="Submit"/>
</LinearLayout>
</ScrollView>
AndroidManifest.xml:
<activity
android:name=".MainActivity"
android:windowSoftInputMode="stateHidden|adjustPan">
</activity>
Sources
- Hiding the Android Soft Keyboard Programmatically on Button Click and Touch Outside
- How to hide soft keyboard on android after clicking outside EditText? - Stack Overflow
- How can I close/hide the Android soft keyboard programmatically? - Stack Overflow
- A Guide to Programmatically Hide the Android Soft Keyboard
- How to hide a soft keyboard on android after clicking outside EditText using Kotlin? - Tutorialspoint
Conclusion
To programmatically hide the Android soft keyboard, you have several effective approaches:
- Use InputMethodManager: The most reliable method is calling
hideSoftInputFromWindow()with the view’s window token - Override dispatchTouchEvent: Provides comprehensive touch event handling across the entire activity
- Combine multiple approaches: Use button click listeners, touch listeners, and dispatch overrides for robust behavior
- Configure windowSoftInputMode: Set appropriate manifest settings for initial keyboard state
The key considerations are:
- Always clear focus from EditText after hiding the keyboard
- Handle both button clicks and touch events for complete user experience
- Consider accessibility and edge cases in your implementation
- Test on different Android versions and screen sizes
For most applications, the combination of dispatchTouchEvent override and button click listeners provides the most complete solution for hiding the soft keyboard programmatically when users interact with your UI.