Закрыть / скрыть программную клавиатуру Android - PullRequest
3500 голосов
/ 10 июля 2009

У меня есть EditText и Button в моем макете.

После записи в поле редактирования и нажатия на Button я хочу скрыть виртуальную клавиатуру. Я предполагаю, что это простой кусок кода, но где я могу найти пример этого?

Ответы [ 92 ]

4320 голосов
/ 10 июля 2009

Вы можете заставить Android скрывать виртуальную клавиатуру, используя InputMethodManager , вызывая hideSoftInputFromWindow, передавая токен окна, содержащего ваш сфокусированный вид.

// Check if no view has focus:
View view = this.getCurrentFocus();
if (view != null) {  
    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

Это заставит клавиатуру быть спрятанной во всех ситуациях. В некоторых случаях вы захотите передать InputMethodManager.HIDE_IMPLICIT_ONLY в качестве второго параметра, чтобы гарантировать, что вы скрываете клавиатуру только тогда, когда пользователь явно не заставлял ее появляться (удерживая меню).

Примечание: Если вы хотите сделать это в Kotlin, используйте: context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

Синтаксис Котлина

// Check if no view has focus:
 val view = this.currentFocus
 view?.let { v ->
  val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager 
  imm?.let { it.hideSoftInputFromWindow(v.windowToken, 0) }
 }
1602 голосов
/ 22 июля 2013

Чтобы прояснить это безумие, я хотел бы начать с извинения от имени всех пользователей Android за совершенно нелепое обращение Google с программной клавиатурой. Причина в том, что существует так много разных ответов на один и тот же простой вопрос, потому что этот API, как и многие другие в Android, разработан ужасно. Я не могу придумать никакого вежливого способа заявить об этом.

Я хочу спрятать клавиатуру. Я ожидаю предоставить Android следующее утверждение: Keyboard.hide(). Конец. Большое спасибо. Но у Android есть проблема. Вы должны использовать InputMethodManager, чтобы скрыть клавиатуру. Хорошо, хорошо, это API-интерфейс Android к клавиатуре. НО! Вам необходимо иметь Context, чтобы получить доступ к IMM. Теперь у нас есть проблема. Возможно, я захочу спрятать клавиатуру от статического или служебного класса, который не нужен или не нужен для любого Context. или И еще хуже, IMM требует, чтобы вы указали, какую View (или еще хуже, какую Window) вы хотите скрыть клавиатуру ОТ.

Это то, что делает скрытие клавиатуры таким сложным. Уважаемый Google: Когда я просматриваю рецепт торта, на Земле нет ни одного RecipeProvider, который отказался бы предоставить мне этот рецепт, если я сначала не отвечу, КТО будет съеден торт И где он будет его есть! !

Эта печальная история заканчивается ужасной правдой: чтобы скрыть клавиатуру Android, вам потребуется предоставить 2 формы идентификации: Context и View или Window.

Я создал метод статической утилиты, который может выполнять работу ОЧЕНЬ беспроблемно, при условии, что вы вызываете его из Activity.

public static void hideKeyboard(Activity activity) {
    InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    //Find the currently focused view, so we can grab the correct window token from it.
    View view = activity.getCurrentFocus();
    //If no view currently has focus, create a new one, just so we can grab a window token from it
    if (view == null) {
        view = new View(activity);
    }
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

Помните, что этот служебный метод работает ТОЛЬКО при вызове из Activity! Приведенный выше метод вызывает getCurrentFocus целевого объекта Activity, чтобы получить соответствующий маркер окна.

Но предположим, что вы хотите скрыть клавиатуру от EditText, размещенного на DialogFragment? Вы не можете использовать метод выше для этого:

hideKeyboard(getActivity()); //won't work

Это не будет работать, потому что вы будете передавать ссылку на хост Fragment Activity, который не будет иметь сфокусированного управления, пока отображается Fragment! Вот Это Да! Итак, чтобы скрыть клавиатуру от фрагментов, я прибегаю к более низкому уровню, более распространенному и более уродливому:

public static void hideKeyboardFrom(Context context, View view) {
    InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

Ниже приведена дополнительная информация, полученная из-за потраченного времени в погоне за этим решением:

Об окне SoftInputMode

Есть еще один момент раздора, о котором нужно знать. По умолчанию Android автоматически назначит начальный фокус первому EditText или фокусируемому элементу управления в Activity. Естественно, что InputMethod (обычно это программная клавиатура) будет реагировать на событие фокуса, показывая себя. Атрибут windowSoftInputMode в AndroidManifest.xml, установленный на stateAlwaysHidden, заставляет клавиатуру игнорировать этот автоматически назначенный начальный фокус.

<activity
    android:name=".MyActivity"
    android:windowSoftInputMode="stateAlwaysHidden"/>

Почти невероятно, что, похоже, ничего не делает для предотвращения открытия клавиатуры при прикосновении к элементу управления (если focusable="false" и / или focusableInTouchMode="false" не назначены элементу управления). По-видимому, настройка windowSoftInputMode применяется только к событиям автоматической фокусировки, а не к событиям фокусировки, вызванным событиями касания.

Следовательно, stateAlwaysHidden действительно ОЧЕНЬ плохо назван. Возможно, вместо этого следует назвать ignoreInitialFocus.

Надеюсь, это поможет.


ОБНОВЛЕНИЕ: больше способов получить маркер окна

Если нет сфокусированного представления (например, это может произойти, если вы только что изменили фрагменты), есть другие представления, которые предоставят полезный маркер окна.

Это альтернативы приведенному выше коду if (view == null) view = new View(activity); Они не относятся явно к вашей деятельности.

Внутри класса фрагмента:

view = getView().getRootView().getWindowToken();

С учетом фрагмента fragment в качестве параметра:

view = fragment.getView().getRootView().getWindowToken();

Начиная с вашего тела контента:

view = findViewById(android.R.id.content).getRootView().getWindowToken();

ОБНОВЛЕНИЕ 2: Снимите фокус, чтобы не показывать клавиатуру снова, если вы откроете приложение из фона

Добавьте эту строку в конец метода:

view.clearFocus();

775 голосов
/ 13 января 2010

Также полезно скрыть софт-клавиатуру:

getWindow().setSoftInputMode(
    WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
);

Это можно использовать для подавления программируемой клавиатуры до тех пор, пока пользователь фактически не коснется представления редактирования текста.

326 голосов
/ 29 февраля 2012

У меня есть еще одно решение, чтобы скрыть клавиатуру:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);

Здесь передаются HIDE_IMPLICIT_ONLY в позиции showFlag и 0 в позиции hiddenFlag. Он принудительно закроет мягкую клавиатуру.

142 голосов
/ 12 февраля 2010

Решение Мейера у меня тоже работает. В моем случае верхний уровень моего приложения - tabHost, и я хочу скрыть ключевое слово при переключении вкладок - я получаю маркер окна из представления tabHost.

tabHost.setOnTabChangedListener(new OnTabChangeListener() {
    public void onTabChanged(String tabId) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(tabHost.getApplicationWindowToken(), 0);
    }
}
130 голосов
/ 04 декабря 2009

Пожалуйста, попробуйте этот код ниже onCreate()

EditText edtView=(EditText)findViewById(R.id.editTextConvertValue);
edtView.setInputType(0);
122 голосов
/ 17 августа 2011

Обновление: Я не знаю, почему это решение больше не работает (я только что протестировал на Android 23). Пожалуйста, используйте вместо этого Saurabh Pareek . Вот оно:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
//Hide:
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
//Show
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

Старый ответ:

//Show soft-keyboard:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
//hide keyboard :
 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
79 голосов
/ 04 мая 2012
protected void hideSoftKeyboard(EditText input) {
    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(input.getWindowToken(), 0);    
}
66 голосов
/ 28 января 2012

Если все остальные ответы здесь не работают так, как вы хотели бы, есть другой способ ручного управления клавиатурой.

Создайте функцию, которая будет управлять некоторыми из свойств EditText:

public void setEditTextFocus(boolean isFocused) {
    searchEditText.setCursorVisible(isFocused);
    searchEditText.setFocusable(isFocused);
    searchEditText.setFocusableInTouchMode(isFocused);

    if (isFocused) {
        searchEditText.requestFocus();
    }
}

Затем убедитесь, что при фокусировке EditText вы открываете / закрываете клавиатуру:

searchEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (v == searchEditText) {
            if (hasFocus) {
                // Open keyboard
                ((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(searchEditText, InputMethodManager.SHOW_FORCED);
            } else {
                // Close keyboard
                ((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(searchEditText.getWindowToken(), 0);
            }
        }
    }
});

Теперь, когда вы хотите открыть клавиатуру вручную, звоните:

setEditTextFocus(true);

А для закрытия звонка:

setEditTextFocus(false);
57 голосов
/ 23 марта 2013

Saurabh Pareek пока имеет лучший ответ.

Можно использовать и правильные флаги.

/* hide keyboard */
((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
    .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

/* show keyboard */
((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
    .toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);

Пример реального использования

/* click button */
public void onClick(View view) {      
  /* hide keyboard */
  ((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
      .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

  /* start loader to check parameters ... */
}

/* loader finished */
public void onLoadFinished(Loader<Object> loader, Object data) {
    /* parameters not valid ... */

    /* show keyboard */
    ((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
        .toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);

    /* parameters valid ... */
}
...