web-dev-qa-db-fra.com

Comment masquer le clavier virtuel sur Android après avoir cliqué en dehors de EditText?

Ok tout le monde sait que pour cacher un clavier il faut mettre en place:

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

Mais le gros problème ici est de savoir comment cacher le clavier lorsque l’utilisateur touche ou sélectionne un autre endroit qui n’est pas une EditText ou le softKeyboard?

J'ai essayé d'utiliser la 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 vue à défilement.

J'ai essayé d'implémenter un contact, un clic, un auditeur sans succès.

J'ai même essayé d'implémenter 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 sur laquelle l'utilisateur a cliqué.

Y at-il un moyen standard de le faire? sur iPhone, c'était vraiment facile.

300
htafoya

L'extrait suivant masque 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 l'insérer dans une classe d'utilitaires ou, si vous le définissez dans une activité, évitez le paramètre activité ou appelez hideSoftKeyboard(this).

La partie la plus délicate est quand l'appeler. Vous pouvez écrire une méthode qui parcourt chaque View de votre activité et vérifier s'il s'agit d'un instanceof EditText s'il ne s'agit pas d'enregistrer une setOnTouchListener pour ce composant et que tout se mettra en place. Au cas où vous vous demandez comment faire cela, c'est en fait assez simple. Voici ce que vous faites, vous écrivez une méthode récursive comme celle-ci. En fait, vous pouvez l'utiliser pour tout faire, comme la configuration de 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 cette méthode après votre setContentView dans votre activité. Si vous vous demandez quel paramètre vous transmettriez, il s’agit de la variable id du conteneur parent. Attribuez une id à votre conteneur parent comme

<RelativeLayoutPanel Android:id="@+id/parent"> ... </RelativeLayout>

et appelez setupUI(findViewById(R.id.parent)), c'est tout.

Si vous voulez utiliser cela efficacement, vous pouvez créer une variable Activity étendue, y inclure cette méthode et faire en sorte que toutes les autres activités de votre application étendent cette activité et appellent sa setupUI() dans la méthode onCreate().

J'espère que ça aide.

Si vous utilisez plus d'une activité, définissez l'identifiant commun sur la présentation parente, tel que <RelativeLayout Android:id="@+id/main_parent"> ... </RelativeLayout>

Puis étendez une classe de Activity et définissez setupUI(findViewById(R.id.main_parent)) dans sa OnResume() et étendez cette classe au lieu de `` Activityin your program

534
Navneeth G

Vous pouvez y parvenir en procédant comme suit:

  1. Rendre la vue parent (vue du contenu de votre activité) cliquable et focalisable en ajoutant les attributs suivants

        Android:clickable="true" 
        Android:focusableInTouchMode="true" 
    
  2. Implémenter une méthode hideKeyboard ()

        public void hideKeyboard(View view) {
            InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    
  3. Enfin, définissez 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 pourrait ne pas fonctionner si la vue parent est une ScrollView. Dans ce cas, les options clickable et focusableInTouchMode peuvent être ajoutées à la vue directement sous ScrollView.

235
vida

Je trouve la réponse acceptée un peu compliquée.

Voici ma solution. Ajoutez une OnTouchListener à votre mise en page principale, par exemple:

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.

51
roepit

J'ai encore une solution pour cacher le clavier en:

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

Ici, passez HIDE_IMPLICIT_ONLY à la position de showFlag et 0 à la position de hiddenFlag. Il fermera de force le clavier logiciel.

36
Saurabh Pareek

Eh bien, je parviens à résoudre un peu le problème, j’ai modifié le dispatchTouchEvent de mon activité, j’utilise le texte suivant pour masquer 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 simplement une méthode qui renvoie un tableau avec les champs de texte de la vue. Pour éviter de créer ce tableau à chaque contact, j'ai créé un tableau statique appelé sFields, qui est renvoyé à la méthode getFields (). Ce tableau est initialisé sur les méthodes onStart () telles que:

sFields = new EditText[] {mUserField, mPasswordField};


Ce n’est pas parfait, l’heure de l’événement «glisser» n’est basée que sur des méthodes heuristiques; ainsi, elle ne se cache parfois pas lorsqu’on exécute de longs clics. J'ai également fini par créer une méthode pour obtenir tous les editTexts par vue; sinon, le clavier serait masqué et affiché lorsque vous cliquez sur un autre texte EditText.

Néanmoins, des solutions plus propres et plus courtes sont les bienvenues

16
htafoya

Utilisez OnFocusChangeListener .

Par exemple:

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
            hideKeyboard();
        }
    }
});

Update: vous pouvez également remplacer onTouchEvent() dans votre activité et vérifier les coordonnées du contact. Si les coordonnées sont en dehors de EditText, masquez le clavier.

13
Sergey Glotov

J'ai implémenté dispatchTouchEvent dans Activity pour cela:

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!

12
Jishi Chen

Ignorer le dispatchTouchEvent public booléen (événement MotionEvent) dans une 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

10
Hoang Trinh

Je suis conscient que ce fil est assez ancien, que la réponse correcte semble valable et qu'il existe de nombreuses solutions fonctionnelles, mais je pense que l'approche indiquée ci-dessous pourrait présenter un avantage supplémentaire en termes d'efficacité et d'élégance.

J'ai besoin de ce comportement pour toutes mes activités. J'ai donc créé une classe CustomActivity héritant de la classe Activity et "accroché" la fonction dispatchTouchEvent . Il existe principalement deux conditions à prendre en compte:

  1. Si le focus est inchangé et que quelqu'un tape en dehors du champ de saisie actuel, fermez l'IME.
  2. Si la focalisation a changé et que le prochain élément focalisé n'est pas une instance d'un champ de saisie, fermez l'IME.

Ceci 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: De plus, j'attribue ces attributs à la vue racine, ce qui permet de supprimer le focus sur chaque champ de saisie et d'empêcher les champs de saisie de se focaliser sur le démarrage de l'activité (le contenu est alors considéré comme le "capteur de focus"):

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final View view = findViewById(R.id.content);

    view.setFocusable(true);
    view.setFocusableInTouchMode(true);
}
8
fje

J'ai modifié la solution d'Andre Luis IM j'ai réalisé celle-ci:

J'ai créé une méthode utilitaire pour masquer le clavier logiciel de la même manière qu'Andre 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 donnant des performances médiocres, j’ai enregistré OnTouchListener uniquement pour la vue racine. Puisque l'événement bouillonne jusqu'à sa consommation (EditText est l'une des vues qui l'utilise par défaut), s'il arrive à la vue racine, c'est qu'il n'a pas été consommé. Je ferme donc le clavier logiciel.

findViewById(Android.R.id.content).setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Utils.hideSoftKeyboard(activity);
        return false;
    }
});
7
Fernando Camargo

J'ai aimé l'approche consistant à appeler dispatchTouchEvent faite par htafoya, mais:

  • Je n'ai pas compris la partie minuterie (je ne sais pas pourquoi il serait nécessaire de mesurer le temps d'arrêt?)
  • Je n'aime pas enregistrer/désinscrire tous les EditTexts à chaque changement de vue (cela peut prendre pas mal de changements de vues et de modifications dans les hiérarchies complexes)

J'ai donc rendu 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:

Passer d'une EditText à une autre EditText rend le clavier caché et le reshow - dans mon cas, c'est ce que l'on souhaite, car cela montre que vous avez basculé entre deux composants d'entrée.

6
Christian R.

Une méthode plus Kotlin & Material Design utilisant TextInputEditText (cette approche est également compatible avec EditTextView ) ...

1.Faites la vue parente (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 (dans un fichier ViewExtension.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. Implémentez la méthode onFocusChanged pour masquer le clavier lorsque la vue n'est pas centré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.Il suffit d'appeler 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.

5
Phil

Plaidoyer: Je reconnais ne pas avoir de poids, mais prenez ma réponse au sérieux. 

Problème: Fermez le clavier logiciel lorsque vous cliquez loin du clavier ou modifiez le texte avec un code minimal.

Solution: Bibliothèque externe appelée Butterknife.

_ {One Line 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: Liez OnClick Listener à l'ID parent de la disposition XML de l'activité, de sorte que tout clic sur la disposition (et non sur le texte ou le clavier édité) exécute cet extrait de code masquant le clavier.

Exemple: Si votre fichier de mise en page est R.layout.my_layout et votre identifiant de mise en page est R.id.my_layout_id, votre appel de reliure Butterknife doit alors ressembler à ceci:

(@OnClick(R.id.my_layout_id) 
public void yourMethod {
    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}

Butterknife Documentation Lien:http://jakewharton.github.io/butterknife/

Plug: Butterknife va révolutionner votre développement Android. Considère-le.

Remarque: Le même résultat peut être obtenu sans utiliser la bibliothèque externe Butterknife. Définissez simplement OnClickListener sur la disposition parent comme décrit ci-dessus.

5
Charles Woodson

Voici une autre variante de la réponse de fje qui aborde les problèmes soulevés par sosite.

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 notons la vue actuellement focalisée (le cas échéant) et si le contact était à l'intérieur, sauvegardant ces deux informations pour plus tard.

Sur l’action ascendante, nous envoyons d’abord, pour permettre à une autre vue de se focaliser potentiellement. Si, après cela, la vue actuellement active est la vue initiale, et que la touche enfoncée se trouvait à l'intérieur de cette vue, nous laissons le clavier ouvert.

Si la vue actuellement focalisée est différente de la vue initialement focalisée et s'il s'agit d'une EditText, nous laissons également le clavier ouvert.

Sinon on le ferme.

Donc, pour résumer, cela fonctionne comme suit:

  • lorsque vous touchez à l'intérieur d'une EditText actuellement focalisée, le clavier reste ouvert
  • lorsque vous passez d'une EditText centrée à une autre EditText, le clavier reste ouvert (ne ferme pas et ne rouvre pas)
  • lorsque vous touchez n'importe où en dehors d'une EditText actuellement active qui n'est pas une autre EditText, le clavier se ferme
  • lorsque vous appuyez longuement sur une EditText pour afficher la barre d’action contextuelle (avec les boutons Couper/Copier/Coller), le clavier reste ouvert, même si l’action UP s’est déroulée en dehors de la EditText focalisée (qui a été déplacée pour permettre la TAXI). Notez cependant que lorsque vous appuyez sur un bouton de l’ACR, le clavier se ferme. Cela peut être souhaitable ou non. si vous voulez couper/copier d'un champ et le coller dans un autre, ce le sera. Si vous voulez coller dans la même EditText, ce ne serait pas.
  • lorsque la EditText focalisée est en bas de l'écran et que vous cliquez longuement sur un texte pour le sélectionner, la EditText reste active et le clavier s'ouvre comme vous le souhaitez, car nous effectuons la coche "toucher est dans les limites de la vue" sur la 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);
    }
    
3
Andy Dennie

Je trouve le bit de réponse accepté complexe pour cette simple exigence. 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;
        }
    });
3
Joohay

c'est trop simple, il suffit de rendre votre mise en page récente cliquable une mise au point par ce code:

Android:id="@+id/loginParentLayout"
Android:clickable="true"
Android:focusableInTouchMode="true"

et écrivez ensuite une méthode et un OnClickListner pour cette présentation, de sorte que lorsque vous touchez la présentation la plus supérieure, vous appelez une méthode dans laquelle vous écrirez du code pour supprimer 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 de listner: -

 public void hideKeyboard(View view) {
     InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }
3
swarnim dixit

Méthode d'affichage/masquage du 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

3
lalosoft

J'ai affiné la méthode, mis le code suivant dans une classe d'utilitaires d'interface utilisateur (de préférence, pas nécessairement) afin qu'il soit accessible à partir de toutes vos classes d'activité ou de fragments pour remplir son objectif.

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, disons par exemple que vous devez appeler l'activité, appelez-la comme suit:

UIutils.serachAndHideSoftKeybordFromView(findViewById(Android.R.id.content), YourActivityName.this);

Remarquer 

findViewById (Android.R.id.content)

Cela nous donne la vue racine du groupe actuel (vous ne devez pas avoir défini l'id sur la vue racine).

À votre santé :)

2
Uzair

En kotlin, nous pouvons faire ce qui suit. Pas besoin d'itérer toutes les vues. Cela fonctionnera aussi pour les fragments.

override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
    currentFocus?.let {
        val imm: InputMethodManager = getSystemService(
            Context.INPUT_METHOD_SERVICE
        ) as (InputMethodManager)
        imm.hideSoftInputFromWindow(it.windowToken, 0)
    }
    return super.dispatchTouchEvent(ev)
}
2
Sai Kiranjangala

Essayez de mettre stateHidden sur en tant que votre valeur d'activité windowSoftInputMode

http://developer.Android.com/reference/Android/R.attr.html#windowSoftInputMode

Par exemple pour votre activité:

this.getWindow().setSoftInputMode(
    WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
2
Alex Volovoy

Il existe une approche plus simple, basée sur le même problème iPhone. Remplacez simplement la disposition 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;
                }
            });
2
Alex R. R.

Ceci est une version légèrement modifiée de la réponse de fje qui fonctionne généralement parfaitement.

Cette version utilise ACTION_DOWN, une action de défilement ferme donc le clavier . Elle ne propage pas l'événement à moins que vous ne cliquiez sur un autre texte d'édition. Cela signifie que cliquer n'importe où en dehors de votre EditText, même sur un autre clic, 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);
}
1
Cadmonkey33

Ajoutez simplement ce code dans la classe @Overide

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())
            ((InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((this.getWindow().getDecorView().getApplicationWindowToken()), 0);
    }
    return super.dispatchTouchEvent(ev);
}
1
Haseeb Javed

Pour résoudre ce problème, vous devez d'abord utiliser setOnFocusChangeListener de cet 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");
                }
            }
        });

ensuite, vous devez remplacer dispatchTouchEvent dans l'activité contenant 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, qu’arrivera-t-il lorsqu'un utilisateur cliquera à l’extérieur puis, d’abord, ce dispatchTouchEvent sera appelé, puis le focus de l’éditext sera maintenant effacé de votre editext maintenant que votre OnFocusChangeListener sera appelé;

1
Sudhanshu Gaur

C'est peut-être vieux, mais j'ai réussi à implémenter 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 consiste à créer une classe Helper et chaque mise en page relative/linéaire du conteneur doit l'implémenter. 

**** Notez que seul le conteneur principal doit implémenter cette classe (pour l'optimisation) ****

et l'implémenter comme ceci:

Parent.setOnClickListener( new DismissKeyboardListener(this) ); 

le mot clé c'est pour l'activité. Donc, si vous êtes sur un fragment, vous utilisez comme getActivity ();

--- Bravo si cela vous aide ... --- Bravo Ralph ---

1
ralphgabb

J'ai fait comme ça:

@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);
  }

Terminé

1
Hiren Patel
@Override
    public boolean onTouchEvent(MotionEvent event) {
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.
                INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        return true;
    }
1
Jeffy

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);
 }
1
icebail

Une autre idée est de remplacer la méthode onInterceptTouchEvent dans la vue racine de votre activité. 

L'événement tactile passe de la vue la plus en avant à l'écran (où l'événement tactile s'est produit) à la pile de vues appelant la méthode onTouch jusqu'à ce que l'une des vues redevienne vraie, indiquant que l'événement tactile a été consommé. Étant donné que de nombreuses vues consomment l'événement tactile par défaut (c'est le cas de EditText ou TextView, par exemple), l'événement ne parvient pas à la méthode racine View onTouch de l'activité.

Mais avant de faire cette traversée, l'événement tactile emprunte un autre chemin, allant de la vue racine à l'arborescence de la vue jusqu'à la vue la plus en avant. Cette traversée se fait en appelant onInterceptTouchEvent. Si la méthode retourne true, elle intercepte l'événement ... nahhh, mais c'est un petit truc, je ne pense pas que vous souhaitiez faire cela ni connaître les détails. Ce que vous devez savoir, c'est que vous pouvez remplacer cette méthode dans la vue racine de votre activité et y insérer le code permettant de masquer le clavier si nécessaire.

0
Andre Luis IM

Eh bien, vous pouvez utiliser ce code, utilisez votre identifiant de mise en page principale au lieu de "mainRelativeLayout" 

//hide Soft keyboard on click outside  the input text
    findViewById(R.id.mainRelativeLayout).setOnClickListener(new 
View.OnClickListener() {
        @Override
        public void onClick(View v) {
            InputMethodManager im = (InputMethodManager) 
getSystemService(INPUT_METHOD_SERVICE);
            im.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 
0);
        }

    });
0
vinod wakade

Vous pouvez facilement remplacer l'événement onKey () de l'activité et des 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;
}
0
Ajith Memana

Celui-ci est la solution la plus simple pour moi (et élaborée par moi).

C'est la méthode pour cacher le clavier.

public void hideKeyboard(View view){
        if(!(view instanceof EditText)){
            InputMethodManager inputMethodManager=(InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
        }
    }

maintenant, définissez l'attribut onclick de la présentation parente de l'activité sur la méthode ci-dessus hideKeyboard à partir du mode Création de votre fichier XML ou en écrivant le code ci-dessous dans la vue Texte de votre fichier XML.

Android:onClick="hideKeyboard"
0
NullByte08

Vous pouvez essayer le moyen ci-dessous, cela fonctionne très bien pour moi :) 

Cette manière peut être appliquée pour l'activité ou le fragment et est également compatible avec ScrollView. 

Nous plaçons ScrollView en tant que disposition de niveau supérieur, déclarons id parentView pour le LinearLayout et ajoutons deux attributs, comme ci-dessous: 

Android:id="@+id/parentView"
Android:clickable="true"
Android:focusableInTouchMode="true"

Dans le code, écrivez une fonction comme ci-dessous: 

public static void hideSoftKeyboard (Activity activity) {
        InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
    }

Enregistrez ensuite un programme OnFocusChangeListener pour la vue racine (méthode d'écriture dans onCreate) afin que tout le texte d'édition dans l'activité soit affecté:

parentLayout.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    hideSoftKeyboard(your_activity_name.this);
                }
            }
        });
0
Dang Nguyen

J'ai réussi à cacher le clavier de l'intérieur onItemClickAutoCompleteTextView

public void onItemClick(AdapterView<?> adapterViewIn, View viewIn, int indexSelected, long arg3) {
     InputMethodManager imm = (InputMethodManager) getSystemService(viewIn.getContext().INPUT_METHOD_SERVICE);
     imm.hideSoftInputFromWindow(viewIn.getApplicationWindowToken(), 0);
     // your code HERE
}
0
tony gil

salut les gars, j'ai une solution simple pour ce problème et cette solution peut être utilisée pour un simple enregistrement ou un formulaire de connexion . ma solution est la même que celle que j'ai implémentée dans l'écouteur iOS setontouch to Main view 

activity_main.xml ajouter un identifiant à votre mise en page 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;
            }
        });
0
Swap-IOS-Android

Ma solution cache le clavier sur un clic extérieur dans toute activité, avec tous les textes d'édition. Sans les spécifier un par un.

Ajoutez d’abord à la vue racine de la mise en page XML: Android: clickable = "true" Android: focusableInTouchMode = "true"

Ensuite, créez une seule propriété parent de toutes les activités que vous souhaitez masquer au clavier et spécifiez la méthode onResume ():

 @Override
    protected void onResume() {
        super.onResume();
        //getting Root View that gets focus
        View rootView =((ViewGroup)findViewById(Android.R.id.content)).
                getChildAt(0);
        rootView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    hideKeyboard(AbstractActivity.this);
                }
            }
        });
    }

Prolongez votre activité avec cette activité générale (puissance d’héritage!) Et c’est tout, chaque fois que tout EditText (sur une activité étendue) perd son focus, le clavier est masqué.

P.S. Méthode hideKeyboard:

public static void hideKeyboard(Activity context) {
    InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow( context.getCurrentFocus().getWindowToken(), 0);
}

context.getCurrentFocus () n'a pas besoin de spécifier une vue EditText spécifique.

0
Misha Akopov

Remplacez simplement le code ci-dessous dans l'activité

 @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (getCurrentFocus() != null) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    }
    return super.dispatchTouchEvent(ev);
}
0
sumit sonawane

Je travaille avec une légère variante de la solution de Fernando Camarago. Dans ma méthode onCreate, j'attache un seul onTouchListener à la vue racine mais j'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 séparée Utils est ...

    public static void hideSoftKeyboard(View v) {
    InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
0
AndyMc

Je pensais que ce problème . Premièrement, je pense que setOnTouchListener n’est pas une solution simple . Je pense donc que dispatchTouchEvent est la meilleure solution simple.

public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getAction() == KeyEvent.ACTION_UP) {
        View v = getCurrentFocus();
        if (v instanceof EditText) {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        }
    }
    return super.dispatchKeyEvent(event);
}

ici, un élément important est ACTION_UP.

J'ai supposé que EditText ne montrait que le clavier logiciel, sinon ne montrait pas le clavier . J'ai testé sur Android5.0.1 (G3.cat6 de LG).

si vous avez besoin de vérification par glisser-déposer, clic long, ..., affichez les commentaires ci-dessus.

0
Hogun