Comment masquer le clavier logiciel sur android après avoir cliqué sur EditText extérieur?
Ok tout le monde sait que pour masquer un clavier, vous devez implémenter:
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
, Mais le gros problème ici est de savoir comment masquer le clavier lorsque l'utilisateur touche ou sélectionne tout autre endroit qui n'est pas un EditText
ou le softKeyboard?
J'ai essayé d'utiliser le onTouchEvent()
sur mon parent Activity
mais cela ne fonctionne que si l'utilisateur touche en dehors de toute autre vue et qu'il n'y a pas de scrollview.
J'ai essayé d'implémenter un écouteur tactile, clic, focus sans aucun succès.
J'ai même essayé de mettre en œuvre mon propre scrollview pour intercepter les événements tactiles mais je ne peux obtenir que les coordonnées de l'événement et non la vue cliquée.
Existe-t-il un moyen standard de le faire?? dans iPhone, il était vraiment facile.
30 réponses
L'extrait suivant cache simplement le clavier:
public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager =
(InputMethodManager) activity.getSystemService(
Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(
activity.getCurrentFocus().getWindowToken(), 0);
}
Vous pouvez mettre cela dans une classe utilitaire, ou si vous le définissez dans une activité, évitez le paramètre activity ou appelez hideSoftKeyboard(this)
.
La partie la plus délicate est quand l'appeler. Vous pouvez écrire une méthode qui parcourt chaque View
dans votre activité, et vérifier si c'est un instanceof EditText
si ce n'est pas enregistrer un setOnTouchListener
à ce composant et tout tombera en place. Dans le cas où vous vous demandez comment faire, c'est dans fait assez simple. Voici ce que vous faites, vous écrivez une méthode récursive comme la suivante, en fait vous pouvez l'utiliser pour faire n'importe quoi, comme configurer des polices de caractères personnalisées, etc... Voici la méthode
public void setupUI(View view) {
// Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText)) {
view.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard(MyActivity.this);
return false;
}
});
}
//If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
C'est tout, appelez simplement cette méthode après vous setContentView
dans votre activité. Dans le cas où vous vous demandez quel paramètre vous passeriez, c'est le id
du conteneur parent. Attribuer un id
à votre conteneur parent comme
<RelativeLayoutPanel android:id="@+id/parent"> ... </RelativeLayout>
Et appelez setupUI(findViewById(R.id.parent))
, c'est tout.
Si vous si vous voulez l'utiliser efficacement, vous pouvez créer un Activity
étendu et mettre cette méthode, et faire en sorte que toutes les autres activités de votre application étendent cette activité et appellent son setupUI()
dans la méthode onCreate()
.
J'espère que ça aide.
Si vous utilisez plus de 1 activité, définissez l'ID commun à la disposition parente comme
<RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>
Ensuite, étendez une classe à partir de Activity
et définissez setupUI(findViewById(R.id.main_parent))
dans son OnResume()
et étendez cette classe au lieu de " Activityin your program
Vous pouvez y parvenir en procédant comme suit:
-
Rendez la vue parent(vue du contenu de votre activité) cliquable et focalisable en ajoutant les attributs suivants
android:clickable="true" android:focusableInTouchMode="true"
-
Implémente une méthode hideKeyboard ()
public void hideKeyboard(View view) { InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); }
-
Enfin, définissez le onFocusChangeListener de votre edittext.
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { hideKeyboard(v); } } });
Comme indiqué dans l'un des commentaires ci-dessous, cela peut ne pas fonctionner si la vue parent est un ScrollView. Dans de tels cas, l' clickable et focusableInTouchMode peuvent être ajoutés sur la vue directement sous le ScrollView.
Je trouve la réponse acceptée un peu compliquée.
Voici ma solution. Ajouter un OnTouchListener
à votre page principale, c'est à dire.:
findViewById(R.id.mainLayout).setOnTouchListener(this)
Et mettez le code suivant dans la méthode onTouch.
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
De cette façon, vous n'avez pas à parcourir toutes les vues.
J'ai une solution de plus pour cacher le clavier par:
InputMethodManager imm = (InputMethodManager) getSystemService(
Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
Passent Ici HIDE_IMPLICIT_ONLY
, à showFlag
et 0
, à hiddenFlag
.
Il fermera avec force le clavier logiciel.
Eh bien, je parviens à résoudre un peu le problème, j'ai dépassé le dispatchTouchEvent sur mon activité, là j'utilise ce qui suit pour cacher le clavier.
/**
* Called to process touch screen events.
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
touchDownTime = SystemClock.elapsedRealtime();
break;
case MotionEvent.ACTION_UP:
//to avoid drag events
if (SystemClock.elapsedRealtime() - touchDownTime <= 150){
EditText[] textFields = this.getFields();
if(textFields != null && textFields.length > 0){
boolean clickIsOutsideEditTexts = true;
for(EditText field : textFields){
if(isPointInsideView(ev.getRawX(), ev.getRawY(), field)){
clickIsOutsideEditTexts = false;
break;
}
}
if(clickIsOutsideEditTexts){
this.hideSoftKeyboard();
}
} else {
this.hideSoftKeyboard();
}
}
break;
}
return super.dispatchTouchEvent(ev);
}
EDIT: la méthode getFields () est juste une méthode qui renvoie un tableau avec les champs de texte dans la vue. Pour éviter de créer ce tableau à chaque contact, j'ai créé un tableau statique appelé sFields, qui est retourné à la méthode getFields (). Ce tableau est initialisé sur les méthodes onStart() telles que comme:
sFields = new EditText[] {mUserField, mPasswordField};
Ce n'est pas parfait, L'Heure de l'événement de glisser est uniquement basée sur des heuristiques, donc parfois il ne se cache pas lors de longs clics, et j'ai également fini par créer une méthode pour obtenir tous les editTexts par vue; sinon le clavier se cacherait et s'afficherait en cliquant sur un autre EditText.
Pourtant, des solutions plus propres et plus courtes sont les bienvenues
Utilisez OnFocusChangeListener .
Par exemple:
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
hideKeyboard();
}
}
});
Mise à Jour: vous pouvez également remplacer onTouchEvent()
dans votre activité et de vérifier les coordonnées du contact. Si les coordonnées sont en dehors de EditText, masquez le clavier.
J'ai implémenté dispatchTouchEvent dans Activity pour faire ceci:
private EditText mEditText;
private Rect mRect = new Rect();
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
int[] location = new int[2];
mEditText.getLocationOnScreen(location);
mRect.left = location[0];
mRect.top = location[1];
mRect.right = location[0] + mEditText.getWidth();
mRect.bottom = location[1] + mEditText.getHeight();
int x = (int) ev.getX();
int y = (int) ev.getY();
if (action == MotionEvent.ACTION_DOWN && !mRect.contains(x, y)) {
InputMethodManager input = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
input.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}
return super.dispatchTouchEvent(ev);
}
Et je l'ai testé, fonctionne parfaitement!
Remplacer le dispatchTouchEvent booléen public (événement MotionEvent) dans N'importe quelle activité (ou étendre la classe D'activité)
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
View view = getCurrentFocus();
boolean ret = super.dispatchTouchEvent(event);
if (view instanceof EditText) {
View w = getCurrentFocus();
int scrcoords[] = new int[2];
w.getLocationOnScreen(scrcoords);
float x = event.getRawX() + w.getLeft() - scrcoords[0];
float y = event.getRawY() + w.getTop() - scrcoords[1];
if (event.getAction() == MotionEvent.ACTION_UP
&& (x < w.getLeft() || x >= w.getRight()
|| y < w.getTop() || y > w.getBottom()) ) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0);
}
}
return ret;
}
Et c'est tout ce que vous devez faire
Je suis conscient que ce fil est assez vieux, la bonne réponse semble valide et il y a beaucoup de solutions de travail là-bas, mais je pense que l'approche indiquée ci-dessous pourrait avoir un avantage supplémentaire en ce qui concerne l'efficacité et l'élégance.
J'ai besoin de ce comportement pour l'ensemble de mes activités, j'ai donc créé une classe CustomActivity héritant de la classe Activité et "accro" de la dispatchTouchEvent function. Il y a principalement deux conditions à prendre en charge de:
- si le focus est inchangé et que quelqu'un tapote en dehors du champ de saisie actuel, alors fermez L'IME
- si le focus a changé et que l'élément focalisé suivant n'est pas une instance d'un type de champ de saisie, alors ignorez L'IME
C'est mon résultat:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_UP) {
final View view = getCurrentFocus();
if(view != null) {
final boolean consumed = super.dispatchTouchEvent(ev);
final View viewTmp = getCurrentFocus();
final View viewNew = viewTmp != null ? viewTmp : view;
if(viewNew.equals(view)) {
final Rect rect = new Rect();
final int[] coordinates = new int[2];
view.getLocationOnScreen(coordinates);
rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight());
final int x = (int) ev.getX();
final int y = (int) ev.getY();
if(rect.contains(x, y)) {
return consumed;
}
}
else if(viewNew instanceof EditText || viewNew instanceof CustomEditText) {
return consumed;
}
final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0);
viewNew.clearFocus();
return consumed;
}
}
return super.dispatchTouchEvent(ev);
}
Note latérale: en outre, j'attribue ces attributs à la vue racine, ce qui permet de mettre l'accent sur chaque champ de saisie et d'empêcher les champs de saisie de se concentrer sur le démarrage de l'activité (faire de la vue du contenu le "focus catcher"):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final View view = findViewById(R.id.content);
view.setFocusable(true);
view.setFocusableInTouchMode(true);
}
J'ai modifié la solution D'Andre Luis IM j'ai atteint celui-ci:
J'ai créé une méthode utilitaire pour masquer le clavier logiciel de la même manière Qu'André Luiz IM:
public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
Mais au lieu d'enregistrer un OnTouchListener pour chaque vue, qui donne une mauvaise performance, j'ai enregistré L'OnTouchListener pour seulement la vue racine. Puisque l'événement fait des bulles jusqu'à ce qu'il soit consommé (EditText est l'une des vues qui le consomme par défaut), s'il arrive à la vue racine, c'est parce qu'il n'a pas été consommé, donc, je ferme le clavier logiciel.
findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Utils.hideSoftKeyboard(activity);
return false;
}
});
J'ai aimé l'approche de l'appel de dispatchTouchEvent
faite par htafoya, mais:
- Je n'ai pas compris la partie minuterie (Je ne sais pas pourquoi mesurer le temps d'arrêt devrait être nécessaire?)
- Je n'aime pas enregistrer / désenregistrer tous les EditTexts avec chaque changement de vue (pourrait être beaucoup de viewchanges et edittexts dans des hiérarchies complexes)
Donc, j'ai fait cette solution un peu plus facile:
@Override
public boolean dispatchTouchEvent(final MotionEvent ev) {
// all touch events close the keyboard before they are processed except EditText instances.
// if focus is an EditText we need to check, if the touchevent was inside the focus editTexts
final View currentFocus = getCurrentFocus();
if (!(currentFocus instanceof EditText) || !isTouchInsideView(ev, currentFocus)) {
((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
return super.dispatchTouchEvent(ev);
}
/**
* determine if the given motionevent is inside the given view.
*
* @param ev
* the given view
* @param currentFocus
* the motion event.
* @return if the given motionevent is inside the given view
*/
private boolean isTouchInsideView(final MotionEvent ev, final View currentFocus) {
final int[] loc = new int[2];
currentFocus.getLocationOnScreen(loc);
return ev.getRawX() > loc[0] && ev.getRawY() > loc[1] && ev.getRawX() < (loc[0] + currentFocus.getWidth())
&& ev.getRawY() < (loc[1] + currentFocus.getHeight());
}
Il y a un inconvénient:
Passage d'un EditText
à un autre EditText
rend le clavier masquer et reshow-dans mon cas, il est souhaité de cette façon, car il montre que vous avez basculé entre deux composants d'entrée.
Plaidoyer: je reconnais que je n'ai pas d'influence, mais veuillez prendre ma réponse au sérieux.
Problème: désactivez le clavier logiciel lorsque vous cliquez hors du clavier ou modifiez du texte avec un code minimal.
Solution: bibliothèque Externe connu comme Butterknife.
Une Ligne Solution:
@OnClick(R.id.activity_signup_layout) public void closeKeyboard() { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }
Solution Plus Lisible:
@OnClick(R.id.activity_signup_layout)
public void closeKeyboard() {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
Explication: lie OnClick Listener à L'ID parent de la mise en page XML de l'activité, de sorte que tout clic sur la mise en page (pas sur le texte d'édition ou le clavier) exécutera cet extrait de code qui masquera le clavier.
Exemple: Si votre fichier de mise en page est R. layout. my_layout et votre ID de mise en page est R. id. my_layout_id, alors votre appel de liaison Butterknife devrait ressembler à:
(@OnClick(R.id.my_layout_id)
public void yourMethod {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
Lien de Documentation Butterknife: http://jakewharton.github.io/butterknife/
Plug: Butterknife va révolutionner votre développement android. Considérer il.
Remarque:, Le même résultat peut être obtenu sans l'utilisation d'une bibliothèque externe Butterknife. Il suffit de définir un OnClickListener à la disposition parente comme décrit ci-dessus.
Méthode pour afficher / masquer le clavier logiciel
InputMethodManager inputMethodManager = (InputMethodManager) currentActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
if (isShow) {
if (currentActivity.getCurrentFocus() == null) {
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
} else {
inputMethodManager.showSoftInput(currentActivity.getCurrentFocus(), InputMethodManager.SHOW_FORCED);
}
} else {
if (currentActivity.getCurrentFocus() == null) {
inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);
} else {
inputMethodManager.hideSoftInputFromInputMethod(currentActivity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
J'espère qu'ils ont été utiles
Voici une autre variante de la réponse de fje qui aborde les questions soulevées par soite.
L'idée ici est de gérer à la fois les actions down et up dans la méthode dispatchTouchEvent
de l'activité. Sur l'action vers le bas, nous prenons note de la vue actuellement ciblée (le cas échéant) et si le toucher était à l'intérieur, en sauvegardant ces deux bits d'information pour plus tard.
Sur l'action up, nous envoyons d'abord, pour permettre à une autre vue de se concentrer potentiellement. Si après cela, la vue actuellement ciblée est la vue initialement ciblée, et le toucher vers le bas était à l'intérieur de cette vue, puis nous laissons le clavier ouvert.
Si la vue actuellement focalisée est différente de la vue initialement focalisée et c'est un EditText
, alors nous laissons également le clavier ouvert.
Sinon on la ferme.
Donc, pour résumer, cela fonctionne comme suit:
- lorsque vous touchez à l'intérieur d'un concentré actuellement
EditText
, le clavier reste ouvert - lors du passage d'un
EditText
focalisé à un autreEditText
, le clavier reste ouvert (ne ferme pas/rouvre) - lorsque vous touchez n'importe où en dehors d'un
EditText
actuellement focalisé qui n'est pas un autreEditText
, le clavier se ferme - lorsque vous appuyez longuement sur un
EditText
pour faire apparaître la barre d'action contextuelle (avec les boutons couper/copier/coller), le clavier reste ouvert, même si l'action UP a eu lieu en dehors duEditText
focalisé (qui s'est déplacé vers le bas pour faire de la place pour la cabine). Notez, cependant, que lorsque vous appuyez sur un bouton dans la cabine, il fermera le clavier. Cela peut ou peut ne pas être souhaitable; si vous voulez couper / copier d'un champ et coller à un autre, ce serait. Si vous voulez coller dans le mêmeEditText
, il ne serait pas. -
Lorsque le
EditText
focalisé est en bas de l'écran et que vous cliquez longuement sur du texte pour le sélectionner, leEditText
conserve le focus et donc le clavier s'ouvre comme vous le souhaitez, car nous vérifions "le toucher est dans les limites de la vue" sur l'action vers le bas, pas l'action vers le haut.private View focusedViewOnActionDown; private boolean touchWasInsideFocusedView; @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: focusedViewOnActionDown = getCurrentFocus(); if (focusedViewOnActionDown != null) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; focusedViewOnActionDown.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + focusedViewOnActionDown.getWidth(), coordinates[1] + focusedViewOnActionDown.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); touchWasInsideFocusedView = rect.contains(x, y); } break; case MotionEvent.ACTION_UP: if (focusedViewOnActionDown != null) { // dispatch to allow new view to (potentially) take focus final boolean consumed = super.dispatchTouchEvent(ev); final View currentFocus = getCurrentFocus(); // if the focus is still on the original view and the touch was inside that view, // leave the keyboard open. Otherwise, if the focus is now on another view and that view // is an EditText, also leave the keyboard open. if (currentFocus.equals(focusedViewOnActionDown)) { if (touchWasInsideFocusedView) { return consumed; } } else if (currentFocus instanceof EditText) { return consumed; } // the touch was outside the originally focused view and not inside another EditText, // so close the keyboard InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( focusedViewOnActionDown.getWindowToken(), 0); focusedViewOnActionDown.clearFocus(); return consumed; } break; } return super.dispatchTouchEvent(ev); }
C'est trop simple, il suffit de rendre votre mise en page récente cliquable un focusable par ce code:
android:id="@+id/loginParentLayout"
android:clickable="true"
android:focusableInTouchMode="true"
Et puis écrivez une méthode et un OnClickListner pour cette mise en page , de sorte que lorsque la mise en page la plus haute est touchée n'importe où il appellera une méthode dans laquelle vous écrirez du code pour rejeter le clavier. voici le code pour les deux; // vous devez écrire ceci dans OnCreate ()
yourLayout.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
hideKeyboard(view);
}
});
Méthode appelée depuis listner: -
public void hideKeyboard(View view) {
InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Il existe une approche plus simple, basée sur iPhone même problème. Remplacez simplement la mise en page de l'arrière-plan sur l'événement tactile, où le texte d'édition est contenu. Utilisez simplement ce code dans OnCreate de l'activité (login_fondo est la mise en page racine):
final LinearLayout llLogin = (LinearLayout)findViewById(R.id.login_fondo);
llLogin.setOnTouchListener(
new OnTouchListener()
{
@Override
public boolean onTouch(View view, MotionEvent ev) {
InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(
android.content.Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mActivity.getCurrentFocus().getWindowToken(), 0);
return false;
}
});
J'ai raffiné la méthode, mis le code suivant dans une classe D'utilité de L'interface utilisateur (de préférence, pas nécessairement) afin qu'il soit accessible à partir de toutes vos classes D'activité ou de Fragment pour servir son but.
public static void serachAndHideSoftKeybordFromView(View view, final Activity act) {
if(!(view instanceof EditText)) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard(act);
return false;
}
});
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View nextViewInHierarchy = ((ViewGroup) view).getChildAt(i);
serachAndHideSoftKeybordFromView(nextViewInHierarchy, act);
}
}
}
public static void hideSoftKeyboard (Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
Ensuite, dites par exemple que vous devez l'appeler de l'activité, appelez-le comme suit;
UIutils.serachAndHideSoftKeybordFromView(findViewById(android.R.id.content), YourActivityName.this);
Avis
FindViewById (android. r. id. content)
Cela nous donne la vue root du groupe actuel (vous ne devez pas avoir défini l'id sur root vue).
Cheers:)
Essayez de mettre stateHidden sur votre activité windowSoftInputMode
Valeur
Http://developer.android.com/reference/android/R.attr.html#windowSoftInputMode
Par exemple pour votre Activité:
this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
Activité
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
ScreenUtils.hideKeyboard(this, findViewById(android.R.id.content).getWindowToken());
return super.dispatchTouchEvent(ev);
}
ScreenUtils
public static void hideKeyboard(Context context, IBinder windowToken) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS);
}
Un Plus Kotlin & Conception matérielle façon en utilisant TextInputEditText (cette approche est également compatible avec EditTextView)...
1.Rendez la vue parent(vue du contenu de votre activité/fragment) cliquable et focalisable en ajoutant les attributs suivants
android:focusable="true"
android:focusableInTouchMode="true"
android:clickable="true"
2.Créez une extension pour toutes les vues (à l'intérieur D'une ViewExtension.fichier kt par exemple):
fun View.hideKeyboard(){
val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(this.windowToken, 0)
}
3.Créez un BaseTextInputEditText qui hérite de TextInputEditText. Mettre la méthode onFocusChanged pour masquer le clavier lorsque la vue n'est pas focalisée:
class BaseTextInputEditText(context: Context?, attrs: AttributeSet?) : TextInputEditText(context, attrs){
override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
super.onFocusChanged(focused, direction, previouslyFocusedRect)
if (!focused) this.hideKeyboard()
}
}
4.Appelez simplement votre nouvelle vue personnalisée dans votre XML:
<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayout"
...>
<com.your_package.BaseTextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
... />
</android.support.design.widget.TextInputLayout>
C'est tout. Pas besoin de modifier vos contrôleurs (fragment ou activité) pour gérer ce cas répétitif.
Je trouve le bit de réponse accepté complexe pour cette exigence simple. Voici ce qui a fonctionné pour moi sans aucun problème.
findViewById(R.id.mainLayout).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
return false;
}
});
Cela peut être vieux mais je l'ai fait fonctionner en implentant une classe personnalisée
public class DismissKeyboardListener implements OnClickListener {
Activity mAct;
public DismissKeyboardListener(Activity act) {
this.mAct = act;
}
@Override
public void onClick(View v) {
if ( v instanceof ViewGroup ) {
hideSoftKeyboard( this.mAct );
}
}
}
public void hideSoftKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager)
getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
}
La meilleure pratique ici est de créer une classe D'AIDE et chaque disposition relative / linéaire de conteneur devrait l'implémenter.
* * * * Prenez note que seul le conteneur principal doit implémenter cette classe (pour l'optimisation) * * * *
Et implémentez-le comme ceci:
Parent.setOnClickListener( new DismissKeyboardListener(this) );
Le mot clé ceci est pour Activity. donc, si vous êtes sur fragment, vous utilisez comme getActivity ();
- - - pouces vers le haut si cela aide vous... --- santé Ralph - - -
Ceci est une version légèrement modifiée de la réponse de fje qui a principalement fonctionné parfaitement.
Cette version utilise ACTION_DOWN donc l'exécution d'une action de défilement ferme également le clavier. Il ne propage pas non plus l'événement sauf si vous cliquez sur un autre EditText. Cela signifie que cliquer n'importe où en dehors de votre EditText, même sur un autre cliquable, ferme simplement le clavier.
@Override
public boolean dispatchTouchEvent(MotionEvent ev)
{
if(ev.getAction() == MotionEvent.ACTION_DOWN)
{
final View view = getCurrentFocus();
if(view != null)
{
final View viewTmp = getCurrentFocus();
final View viewNew = viewTmp != null ? viewTmp : view;
if(viewNew.equals(view))
{
final Rect rect = new Rect();
final int[] coordinates = new int[2];
view.getLocationOnScreen(coordinates);
rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight());
final int x = (int) ev.getX();
final int y = (int) ev.getY();
if(rect.contains(x, y))
{
super.dispatchTouchEvent(ev);
return true;
}
}
else if(viewNew instanceof EditText || viewNew instanceof CustomEditText)
{
super.dispatchTouchEvent(ev);
return true;
}
final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0);
viewNew.clearFocus();
return true;
}
}
return super.dispatchTouchEvent(ev);
}
J'ai fait de cette façon:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
View view = getCurrentFocus();
if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) {
int scrcoords[] = new int[2];
view.getLocationOnScreen(scrcoords);
float x = ev.getRawX() + view.getLeft() - scrcoords[0];
float y = ev.getRawY() + view.getTop() - scrcoords[1];
if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom())
hideKeyboard(this);
}
return super.dispatchTouchEvent(ev);
}
Masquer le code du clavier :
public static void hideKeyboard(Activity act) {
if(act!=null)
((InputMethodManager)act.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((act.getWindow().getDecorView().getApplicationWindowToken()), 0);
}
Fait
Pour résoudre ce problème, vous devez d'abord utiliser setOnFocusChangeListener de ce Edittext
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
Log.d("focus", "focus loosed");
// Do whatever you want here
} else {
Log.d("focus", "focused");
}
}
});
Et puis ce que vous devez faire est de remplacer dispatchTouchEvent dans l'activité qui contient ce Edittext voir le code ci-dessous
@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())) {
Log.d("focus", "touchevent");
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(event);
}
Maintenant, ce qui se passera, c'est quand un utilisateur clique dehors, alors tout d'abord ce dispatchTouchEvent sera appelé, ce qui effacera le focus de l'editext maintenant votre OnFocusChangeListener sera appelé ce focus a été changé maintenant ici vous peut faire tout ce que vous vouliez faire en espérant que cela fonctionne
@Override
public boolean onTouchEvent(MotionEvent event) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.
INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
return true;
}
Une autre idée est de remplacer la méthode onInterceptTouchEvent
sur la vue racine pour votre activité.
L'événement tactile va de la vue la plus visible sur l'écran (où l'événement tactile s'est produit) vers le bas de la pile de vues appelant la méthode onTouch
jusqu'à ce que l'une des vues renvoie true, indiquant que l'événement tactile a été consommé. Comme une grande partie de la vue consomme l'événement tactile par défaut (c'est le cas de EditText
ou TextView
, par exemple), l'événement n'atteint pas la vue racine de l'activité onTouch
méthode.
Mais, avant de faire cette traversée, l'événement tactile parcourt un autre chemin, allant de la vue racine vers le bas de l'arbre de vue jusqu'à ce qu'il arrive à la vue avant. Cette traversée se fait en appelant onInterceptTouchEvent
. Si la méthode renvoie true, elle intercepte l'événement... nahhh, mais c'est un petit truc, je ne pense pas que vous vouliez faire ça ni connaître les détails. Ce que vous devez savoir, c'est que vous pouvez remplacer cette méthode sur la vue racine pour votre activité, et y mettre le code pour masquer le clavier lorsque cela est nécessaire.
Je l'ai fait travailler avec une légère variante sur la solution de Fernando Camarago. Dans ma méthode onCreate, j'attache un seul onTouchListener à la vue racine mais envoie la vue plutôt que l'activité en tant qu'argument.
findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
Utils.hideSoftKeyboard(v);
return false;
}
});
Dans une classe Utils séparée est...
public static void hideSoftKeyboard(View v) {
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
Vous pouvez facilement remplacer l'événement onKey () dans activity et fragments pour masquer le clavier.
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (keyCode == event.KEYCODE_ENTER) {
intiateLoginProcess();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus()
.getWindowToken(), 0);
return true;
}
}
return false;
}
Hey les gars, j'ai une solution simple pour ce problème et cette solution peut être utilisée pour un simple formulaire d'inscription ou de connexion. ma solution est la même que celle que j'ai implémentée dans iOS setontouch listener to Main view
Activity_main.xml ajoute un ID à votre disposition relative principale android:id="@+id/mainlayout"
Et ajoutez ce code à votre activité
RelativeLayout mainLayout = (RelativeLayout)findViewById(R.id.mainlayout);
mainLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
Log.d("Json Response", "Touch outside");
InputMethodManager inputMethodManager = (InputMethodManager) MainActivity.this.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(MainActivity.this.getCurrentFocus().getWindowToken(), 0);
return false;
}
});