NeuroAgent

How to Hide Android Soft Keyboard: Complete Guide

Learn multiple methods to programmatically hide Android soft keyboard on button click and touch outside. Complete code examples with InputMethodManager and touch event handling.

Question

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?

NeuroAgent

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

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.

java
// 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:

  1. Getting the InputSystemService from the current context
  2. Calling hideSoftInputFromWindow() with the view’s window token
  3. The second parameter (0) represents flags, which can be customized for different behaviors

For hiding the keyboard specifically from an EditText, you can use:

java
// 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:

java
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:

java
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:

java
@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:

  1. Checking if the current focused view is an EditText
  2. Getting the global visible rectangle of the EditText
  3. Comparing the touch coordinates with the EditText boundaries
  4. Hiding the keyboard if the touch is outside the EditText

For Kotlin implementation:

kotlin
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:

xml
<activity
    android:name=".MainActivity"
    android:windowSoftInputMode="stateHidden|adjustPan" />

Common values for windowSoftInputMode:

  • stateHidden: Keyboard is hidden when the activity starts
  • stateAlwaysHidden: Keyboard is always hidden
  • adjustPan: Content pans when keyboard appears
  • adjustResize: Window resizes when keyboard appears

Using ViewTreeObserver

Another approach is to use the ViewTreeObserver to detect layout changes:

java
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:

java
// Using Espresso
onView(withId(R.id.editText)).perform(closeSoftKeyboard());

Complete Example Implementation

Here’s a complete, practical implementation combining multiple approaches:

MainActivity.java:

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
<?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:

xml
<activity
    android:name=".MainActivity"
    android:windowSoftInputMode="stateHidden|adjustPan">
</activity>

Sources

  1. Hiding the Android Soft Keyboard Programmatically on Button Click and Touch Outside
  2. How to hide soft keyboard on android after clicking outside EditText? - Stack Overflow
  3. How can I close/hide the Android soft keyboard programmatically? - Stack Overflow
  4. A Guide to Programmatically Hide the Android Soft Keyboard
  5. 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:

  1. Use InputMethodManager: The most reliable method is calling hideSoftInputFromWindow() with the view’s window token
  2. Override dispatchTouchEvent: Provides comprehensive touch event handling across the entire activity
  3. Combine multiple approaches: Use button click listeners, touch listeners, and dispatch overrides for robust behavior
  4. 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.