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.

286
demandé sur Gowtham Subramaniam 2010-11-12 17:04:10

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

516
répondu Navneeth G 2017-01-29 14:57:54

Vous pouvez y parvenir en procédant comme suit:

  1. Rendez 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émente 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 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.

216
répondu vida 2014-09-11 16:20:04

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.

47
répondu roepit 2015-06-02 14:25:04

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.

35
répondu Saurabh Pareek 2016-07-20 07:38:11

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

16
répondu htafoya 2013-04-01 14:26:57

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.

12
répondu Sergey Glotov 2010-11-12 14:48:00

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!

11
répondu Jishi Chen 2014-05-24 11:25:42

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

10
répondu Hoang Trinh 2014-07-27 13:21:23

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:

  1. si le focus est inchangé et que quelqu'un tapote en dehors du champ de saisie actuel, alors fermez L'IME
  2. 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);
}
9
répondu fje 2013-04-23 18:11:43

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;
    }
});
7
répondu Fernando Camargo 2012-10-12 20:01:35

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.

5
répondu Christian R. 2013-03-20 00:00:27

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.

4
répondu Charles Woodson 2017-05-30 15:09:05

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

3
répondu lalosoft 2012-08-10 18:43:37

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 autre EditText, 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 autre EditText, 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 du EditText 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ême EditText, 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, le EditText 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);
    }
    
3
répondu Andy Dennie 2015-09-24 20:27:25

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);
    }
3
répondu swarnim dixit 2016-10-20 10:52:43

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;
                }
            });
2
répondu Alex R. R. 2012-07-12 08:53:32

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:)

2
répondu Uzair 2016-04-22 06:46:19

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);
2
répondu Alex Volovoy 2016-07-20 07:33:31

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);
 }
2
répondu icebail 2017-11-01 13:39:32

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.

2
répondu Phil 2018-05-01 08:37:38

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;
        }
    });
2
répondu Joohay 2018-05-20 13:59:22

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 - - -

1
répondu ralphgabb 2014-10-17 03:16:25

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);
}
1
répondu Cadmonkey33 2015-05-14 23:39:49

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

1
répondu Hiren Patel 2016-03-01 13:49:07

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

1
répondu Sudhanshu Gaur 2016-04-04 19:41:22
@Override
    public boolean onTouchEvent(MotionEvent event) {
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.
                INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        return true;
    }
1
répondu Jeffy 2016-11-03 17:56:26

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.

0
répondu Andre Luis IM 2010-11-12 14:59:47

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);
}
0
répondu AndyMc 2013-03-04 16:48:53

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;
}
0
répondu Ajith Memana 2014-02-13 08:14:11

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;
            }
        });
0
répondu Swap-IOS-Android 2014-02-28 11:11:29