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

7voto

Adarsh Gumashta Points 470

Pour moi, les choses suivantes ont fonctionné -

1. Ajout android:clickable="true" y android:focusableInTouchMode="true" à la parentLayout de EditText i.e android.support.design.widget.TextInputLayout

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:focusableInTouchMode="true">
<EditText
    android:id="@+id/employeeID"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:ems="10"
    android:inputType="number"
    android:hint="Employee ID"
    tools:layout_editor_absoluteX="-62dp"
    tools:layout_editor_absoluteY="16dp"
    android:layout_marginTop="42dp"
    android:layout_alignParentTop="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_marginRight="36dp"
    android:layout_marginEnd="36dp" />
    </android.support.design.widget.TextInputLayout>

2. Surpassement dispatchTouchEvent dans la classe d'activité et en insérant hideKeyboard() fonction

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View view = getCurrentFocus();
            if (view != null && view instanceof EditText) {
                Rect r = new Rect();
                view.getGlobalVisibleRect(r);
                int rawX = (int)ev.getRawX();
                int rawY = (int)ev.getRawY();
                if (!r.contains(rawX, rawY)) {
                    view.clearFocus();
                }
            }
        }
        return super.dispatchTouchEvent(ev);
    }

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

3. Ajout setOnFocusChangeListener pour EditText

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

7voto

Dennis H. Points 95

Voici ma version basée sur le code de zMan. Il ne cachera pas le clavier si la vue suivante est aussi un texte d'édition. Il ne cachera pas non plus le clavier si l'utilisateur fait simplement défiler l'écran.

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        downX = (int) event.getRawX();
    }

    if (event.getAction() == MotionEvent.ACTION_UP) {
        View v = getCurrentFocus();
        if (v instanceof EditText) {
            int x = (int) event.getRawX();
            int y = (int) event.getRawY();
            //Was it a scroll - If skip all
            if (Math.abs(downX - x) > 5) {
                return super.dispatchTouchEvent(event);
            }
            final int reducePx = 25;
            Rect outRect = new Rect();
            v.getGlobalVisibleRect(outRect);
            //Bounding box is to big, reduce it just a little bit
            outRect.inset(reducePx, reducePx);
            if (!outRect.contains(x, y)) {
                v.clearFocus();
                boolean touchTargetIsEditText = false;
                //Check if another editText has been touched
                for (View vi : v.getRootView().getTouchables()) {
                    if (vi instanceof EditText) {
                        Rect clickedViewRect = new Rect();
                        vi.getGlobalVisibleRect(clickedViewRect);
                        //Bounding box is to big, reduce it just a little bit
                        clickedViewRect.inset(reducePx, reducePx);
                        if (clickedViewRect.contains(x, y)) {
                            touchTargetIsEditText = true;
                            break;
                        }
                    }
                }
                if (!touchTargetIsEditText) {
                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
        }
    }
    return super.dispatchTouchEvent(event);
}

5voto

edc598 Points 82

Vous avez probablement déjà trouvé la réponse à ce problème, mais j'ai cherché comment le résoudre et je n'ai toujours pas trouvé exactement ce que je cherchais, alors je me suis dit que j'allais le poster ici.

Ce que j'ai fait est le suivant (c'est très général, le but est de vous donner une idée de la façon de procéder, copier et coller tout le code ne fonctionnera pas O:D ) :

Tout d'abord, l'EditText et toutes les autres vues que vous souhaitez dans votre programme sont enveloppés dans une vue unique. Dans mon cas, j'ai utilisé un LinearLayout pour envelopper le tout.

<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/mainLinearLayout">
 <EditText
  android:id="@+id/editText"/>
 <ImageView
  android:id="@+id/imageView"/>
 <TextView
  android:id="@+id/textView"/>
 </LinearLayout>

Ensuite, dans votre code, vous devez définir un Touch Listener pour votre LinearLayout principal.

final EditText searchEditText = (EditText) findViewById(R.id.editText);
mainLinearLayout.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            if(searchEditText.isFocused()){
                if(event.getY() >= 72){
                    //Will only enter this if the EditText already has focus
                    //And if a touch event happens outside of the EditText
                    //Which in my case is at the top of my layout
                    //and 72 pixels long
                    searchEditText.clearFocus();
                    InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
            Toast.makeText(getBaseContext(), "Clicked", Toast.LENGTH_SHORT).show();
            return false;
        }
    });

J'espère que cela aidera certaines personnes. Ou au moins qu'il les aidera à commencer à résoudre leur problème.

4voto

J'ai un ListView composé de EditText vues. Le scénario indique qu'après avoir modifié du texte dans une ou plusieurs lignes, nous devons cliquer sur un bouton appelé "terminer". J'ai utilisé onFocusChanged sur le EditText vue à l'intérieur de listView mais après avoir cliqué sur "terminer", les données ne sont pas sauvegardées. Le problème a été résolu en ajoutant

listView.clearFocus();

à l'intérieur du onClickListener pour le bouton "terminer" et les données ont été sauvegardées avec succès.

3voto

user3762471 Points 1

Je pense vraiment qu'il s'agit d'une façon plus robuste d'utiliser les getLocationOnScreen que getGlobalVisibleRect . Parce que je rencontre un problème. Il y a une Listview qui contient un Edittext et qui est défini comme suit ajustpan dans l'activité. Je trouve getGlobalVisibleRect renvoie une valeur qui semble inclure le scrollY, mais le event.getRawY est toujours par l'écran. Le code ci-dessous fonctionne bien.

public boolean dispatchTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        View v = getCurrentFocus();
        if ( v instanceof EditText) {
            if (!isPointInsideView(event.getRawX(), event.getRawY(), v)) {
                Log.i(TAG, "!isPointInsideView");

                Log.i(TAG, "dispatchTouchEvent clearFocus");
                v.clearFocus();
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent( event );
}

/**
 * Determines if given points are inside view
 * @param x - x coordinate of point
 * @param y - y coordinate of point
 * @param view - view object to compare
 * @return true if the points are within view bounds, false otherwise
 */
private boolean isPointInsideView(float x, float y, View view) {
    int location[] = new int[2];
    view.getLocationOnScreen(location);
    int viewX = location[0];
    int viewY = location[1];

    Log.i(TAG, "location x: " + location[0] + ", y: " + location[1]);

    Log.i(TAG, "location xWidth: " + (viewX + view.getWidth()) + ", yHeight: " + (viewY + view.getHeight()));

    // point is inside view bounds
    return ((x > viewX && x < (viewX + view.getWidth())) &&
            (y > viewY && y < (viewY + view.getHeight())));
}

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