Pour aider à clarifier cette folie, je voudrais commencer par m'excuser au nom de tous les utilisateurs d'Android du traitement carrément ridicule de Google pour le clavier logiciel. La raison pour laquelle il y a tant de réponses, chacune différente, pour la même question simple est que cette API, comme beaucoup d'autres dans Android, est horriblement conçue. Je ne peux penser à aucune manière polie de le dire.
Je veux cacher le clavier. Je pense à fournir Android avec l'énoncé suivant: Keyboard.hide()
. La fin. Merci beaucoup. Mais Android a un problème. Vous devez utiliser le InputMethodManager
pour masquer le clavier. D'accord, c'est l'API d'Android pour le clavier. MAIS! Vous devez en avoir un Context
pour avoir accès à l'IMM. Maintenant, nous avons un problème. Je peux vouloir cacher le clavier d'une classe statique ou utilitaire qui n'a aucune utilité ou besoin d'aucune Context
. ou bien pire, IMM demande que vous spécifiiez de quoi View
(ou pire encore, de quoi Window
) vous voulez cacher le clavier.
C'est ce qui rend le masquage du clavier si difficile. Cher Google: Quand je recherche la recette d'un gâteau, il n'y a personne RecipeProvider
sur Terre qui refuserait de me fournir la recette à moins que je ne réponde d'abord QUI le gâteau sera mangé par ET où il sera mangé !!
Cette triste histoire se termine par la vilaine vérité: pour cacher le clavier Android, vous devrez fournir 2 formes d'identification: a Context
et soit a View
soit a Window
.
J'ai créé une méthode utilitaire statique qui peut faire le travail TRÈS solidement, à condition de l'appeler à partir d'un 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);
}
Sachez que cette méthode utilitaire fonctionne UNIQUEMENT lorsqu'elle est appelée à partir d'un Activity
! La méthode ci-dessus appelle getCurrentFocus
la cible Activity
pour récupérer le jeton de fenêtre approprié.
Mais supposons que vous vouliez cacher le clavier d'un EditText
hébergé dans un DialogFragment
? Vous ne pouvez pas utiliser la méthode ci-dessus pour cela:
hideKeyboard(getActivity()); //won't work
Cela ne fonctionnera pas car vous passerez une référence à l' Fragment
hôte de Activity
, qui n'aura aucun contrôle concentré pendant que le Fragment
est affiché! Hou la la! Donc, pour cacher le clavier des fragments, je recourt au niveau inférieur, plus courant et plus laid:
public static void hideKeyboardFrom(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Vous trouverez ci-dessous quelques informations supplémentaires tirées du temps perdu à courir après cette solution:
À propos de windowSoftInputMode
Il y a encore un autre point de discorde à prendre en compte. Par défaut, Android attribuera automatiquement la mise au point initiale au premier EditText
ou au contrôle pouvant être mis au point dans votre Activity
. Il s'ensuit naturellement que InputMethod (généralement le clavier virtuel) répondra à l'événement de focus en se montrant. L' windowSoftInputMode
attribut dans AndroidManifest.xml
, lorsqu'il est défini sur stateAlwaysHidden
, demande au clavier d'ignorer ce focus initial attribué automatiquement.
<activity
android:name=".MyActivity"
android:windowSoftInputMode="stateAlwaysHidden"/>
Presque incroyablement, il ne semble rien faire pour empêcher le clavier de s'ouvrir lorsque vous touchez le contrôle (sauf si focusable="false"
et / ou focusableInTouchMode="false"
sont assignés au contrôle). Apparemment, le paramètre windowSoftInputMode s'applique uniquement aux événements de focus automatique, pas aux événements de focus déclenchés par des événements tactiles.
Par conséquent, stateAlwaysHidden
est TRÈS mal nommé en effet. Il faudrait peut-être l'appeler à la ignoreInitialFocus
place.
J'espère que cela t'aides.
MISE À JOUR: Plus de façons d'obtenir un jeton de fenêtre
S'il n'y a pas de vue ciblée (par exemple, si vous venez de changer des fragments), il existe d'autres vues qui fourniront un jeton de fenêtre utile.
Ce sont des alternatives pour le code if (view == null) view = new View(activity);
ci- dessus. Elles ne se réfèrent pas explicitement à votre activité.
Dans une classe de fragments:
view = getView().getRootView().getWindowToken();
Étant donné un fragment fragment
comme paramètre:
view = fragment.getView().getRootView().getWindowToken();
À partir de votre corps de contenu:
view = findViewById(android.R.id.content).getRootView().getWindowToken();
MISE À JOUR 2: Effacer la mise au point pour éviter d'afficher à nouveau le clavier si vous ouvrez l'application en arrière-plan
Ajoutez cette ligne à la fin de la méthode:
view.clearFocus();