Щоб допомогти роз’яснити це безумство, я хотів би почати з вибачення від імені всіх користувачів Android за відверто смішне поводження Google з м'якою клавіатурою. Причина, що існує так багато відповідей, кожен відрізняється, на той самий простий питання, тому що цей API, як і багато інших в Android, жахливо розроблений. Я не можу придумати жодного ввічливого способу заявити про це.
Я хочу приховати клавіатуру. Я очікую , щоб забезпечити Android з наступним твердженням: Keyboard.hide()
. Кінець. Дуже дякую. Але в Android є проблема. Ви повинні використовувати клавішу " InputMethodManager
приховати" клавіатуру. Гаразд, чудово, це API для клавіатури Android. АЛЕ! Вам потрібно мати Context
доступ, щоб отримати доступ до IMM. Зараз у нас є проблема. Можливо, я захочу сховати клавіатуру від статичного чи утилітного класу, який не має жодної користі та потреби Context
. або І чим гірше, IMM вимагає вказати, що View
(або ще гірше, що Window
) ви хочете приховати від клавіатури ВІД.
Саме це робить приховування клавіатури настільки складним. Шановний Google: Коли я шукаю рецепт торта, RecipeProvider
на Землі немає жодного, який би відмовився надати мені рецепт, якщо я вперше не відповіду, КОМО торт буде з'їдений І де він буде з'їдений !!
Ця сумна історія закінчується потворною правдою: щоб сховати клавіатуру Android, вам потрібно буде надати 2 форми ідентифікації: a Context
і або a, View
або a 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();