Чтобы прояснить это безумие, я хотел бы начать с извинения от имени всех пользователей Android за совершенно нелепое обращение Google с программной клавиатурой. Причина того, что на один и тот же простой вопрос так много ответов, разных, потому что этот API, как и многие другие в Android, разработан ужасно. Я не могу придумать никакого вежливого способа заявить об этом.
Я хочу спрятать клавиатуру. Я ожидаю , чтобы обеспечить Android со следующим утверждением: Keyboard.hide()
. Конец. Большое спасибо. Но у Android есть проблема. Вы должны использовать, InputMethodManager
чтобы скрыть клавиатуру. Хорошо, хорошо, это API Android для клавиатуры. НО! Вы должны иметь для Context
того, чтобы получить доступ к IMM. Теперь у нас есть проблема. Я могу захотеть скрыть клавиатуру от статического или служебного класса, который не нужен и не нужен Context
. или И еще хуже, IMM требует, чтобы вы указали, что View
(или даже хуже, что Window
) вы хотите скрыть клавиатуру ОТ.
Это то, что делает скрытие клавиатуры таким сложным. Уважаемый Google: Когда я ищу рецепт торта, RecipeProvider
на Земле нет ни одного человека , который отказался бы предоставить мне этот рецепт, если я сначала не отвечу, КТО будет съеден торт И где он будет съеден !!
Эта печальная история заканчивается ужасной правдой: чтобы спрятать клавиатуру Android, вам потребуется предоставить две формы идентификации: а 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);
}
Ниже приведена дополнительная информация, полученная из-за потраченного времени в погоне за этим решением:
О программе windowSoftInputMode
Есть еще одна точка зрения, о которой нужно знать. По умолчанию 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();