135 votes

EditText, effacer le focus en touchant l'extérieur

Ma mise en page contient ListView , SurfaceView y EditText . Lorsque je clique sur l'icône EditText il reçoit le focus et le clavier à l'écran s'affiche. Lorsque je clique quelque part en dehors de la fenêtre EditText Il est toujours au centre de l'attention (il ne devrait pas l'être). Je pense que je pourrais configurer OnTouchListener sur les autres vues dans la mise en page et effacer manuellement les EditText L'accent est mis sur le Mais cela semble trop artificiel...

J'ai également la même situation dans l'autre présentation - une vue en liste avec différents types d'éléments, dont certains ont des caractéristiques EditText à l'intérieur. Ils agissent comme je l'ai écrit ci-dessus.

Il s'agit de faire EditText se déconcentrent lorsque l'utilisateur touche quelque chose en dehors de l'écran.

J'ai vu des questions similaires ici, mais je n'ai pas trouvé de solution...

291voto

zMan Points 2769

En s'appuyant sur la réponse de Ken, voici la solution de copier-coller la plus modulaire.

Aucun XML n'est nécessaire.

Mettez-le dans votre activité et il s'appliquera à tous les EditTexts, y compris ceux qui se trouvent dans les fragments de cette activité.

@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())) {
                v.clearFocus();
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent( event );
}

73voto

Ken Points 953

J'ai essayé toutes ces solutions. Celle de edc598 était la plus proche de fonctionner, mais les événements tactiles ne se déclenchaient pas sur d'autres View contenues dans la présentation. Au cas où quelqu'un aurait besoin de ce comportement, voici ce que j'ai fini par faire :

J'ai créé un fichier (invisible) FrameLayout appelé touchInterceptor comme le dernier View dans la mise en page de manière à ce qu'il recouvre tout ( éditer : vous devez également utiliser un RelativeLayout en tant que modèle parent et donnez à l'élément touchInterceptor fill_parent attributs). Je l'ai ensuite utilisé pour intercepter les touches et déterminer si la touche se trouvait au-dessus de l'attribut EditText ou non :

FrameLayout touchInterceptor = (FrameLayout)findViewById(R.id.touchInterceptor);
touchInterceptor.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (mEditText.isFocused()) {
                Rect outRect = new Rect();
                mEditText.getGlobalVisibleRect(outRect);
                if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
                    mEditText.clearFocus();
                    InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
        }
        return false;
    }
});

Renvoyez la valeur false pour que la gestion des contacts soit interrompue.

C'est un peu bricolé, mais c'est la seule chose qui a fonctionné pour moi.

36voto

suber Points 88

Pour la vue parentale de l'EditText, les 3 attributs suivants sont " vrai " :
cliquable , focalisable , focusableInTouchMode .

Pour qu'une vue soit mise en valeur, elle doit remplir ces trois conditions.

Voir Android.view :

public boolean onTouchEvent(MotionEvent event) {
    ...
    if (((viewFlags & CLICKABLE) == CLICKABLE || 
        (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
        ...
        if (isFocusable() && isFocusableInTouchMode()
            && !isFocused()) {
                focusTaken = requestFocus();
        }
        ...
    }
    ...
}

J'espère que cela vous aidera.

36voto

chandan Points 426

Il suffit de placer ces propriétés dans le parent le plus élevé.

android:focusableInTouchMode="true"
android:clickable="true"
android:focusable="true"

18voto

Mike Ortiz Points 2649

La réponse de Ken fonctionne, mais elle est peu pratique. Comme le mentionne pcans dans le commentaire de la réponse, la même chose pourrait être faite avec dispatchTouchEvent. Cette solution est plus propre car elle évite d'avoir à pirater le XML avec un FrameLayout transparent et factice. Voici à quoi cela ressemble :

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    EditText mEditText = findViewById(R.id.mEditText);
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        View v = getCurrentFocus();
        if (mEditText.isFocused()) {
            Rect outRect = new Rect();
            mEditText.getGlobalVisibleRect(outRect);
            if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
                mEditText.clearFocus();
                //
                // Hide keyboard
                //
                InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent(event);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X