52

I just want when click outside the "edittext" to automatically lose focus and hide keyboard. At the moment, if I click on the "edittext" it focuses but i need to hit the back button to unfocus.

JustCurious
  • 1,848
  • 3
  • 30
  • 57
  • Related question: http://stackoverflow.com/q/4165414/782870. I think most of the answers have already been tested and have been found to be working. – vida Feb 27 '14 at 14:09
  • I found this answer: http://stackoverflow.com/a/28939113/2610855 The best one. – Loenix Sep 06 '15 at 09:56
  • You should give Sudhanshu Gaur the Accepted Answer, his solution actually works. – Serj Sagan Jan 24 '21 at 14:22

9 Answers9

45

To solve this problem what you have to do is first use setOnFocusChangeListener of that Edittext

edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus) {
                    Log.d("focus", "focus lost");
                    // Do whatever you want here
                } else {
                    Log.d("focus", "focused");
                }
            }
        });

and then what you need to do is override dispatchTouchEvent in the activity which contains that Edittext see below code

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

Now what will happen is when a user click outside then, firstly this dispatchTouchEvent will get called which then will clear focus from the editext, now your OnFocusChangeListener will get called that focus has been changed, now here you can do anything which you wanted to do, hope it works :)

Sudhanshu Gaur
  • 7,486
  • 9
  • 47
  • 94
  • 1
    I like this method. Additionally, add `android:focusable="true"` and `android:focusableInTouchMode="true"` in layout of the `editText`'s direct parent. – Tanapruk Tangphianphan Jun 21 '17 at 18:10
  • `focus loosed` should be `focus losted` :)) – Stack Aug 12 '17 at 17:43
  • This is a brilliant solution, makes it so much easier and not have to mess with layouts and various view group hierarchies. Bravo! – Jia Tse Nov 22 '18 at 17:23
  • 10
    @Stack it's `focus lost` actually :) – Nahro Sep 10 '19 at 10:07
  • 1
    The first method in your example is unnecessary and distracting from the actual solution, which is the second example `dispatchTouchEvent` – Serj Sagan Jan 24 '21 at 14:20
  • Also, if you are in a `Fragment` you will need to implement the `dispatchTouchEvent` override in the parent `Activity` of the `Fragment.` – Serj Sagan Jan 24 '21 at 14:21
  • how can you do this in recyclerview adapter class and fragment kindly guide me – Adnan haider Mar 25 '21 at 12:57
  • i have recycler view when I swipe up or down it's edit text move to a random place in another edit text list suppose at the first item of recyclerview id is 5 and edit text is 3 then swipe after 3 goes to item id 9 or 12 as like that. kindly if you know about it tell me – Adnan haider Mar 25 '21 at 12:59
  • 1
    This approach worked for me by placing it in the Activity my Fragment was hosted in. I have multiple Fragments with an EditText that would continously blink as focus is not removed on tap outside of it, but only when another EditText is clicked. Thanks for sharing. – kelvin Oct 27 '21 at 15:06
19

@woodshy has the answer for hiding the keyboard, but maybe putting the code in onClick is not as good as putting it in onFocusChanged. As for forcing it to lose focus, you need to set the object you want to transfer the focus to, in its XML file:

android:focusable="true"
android:focusableInTouchMode ="true"
Gary
  • 13,303
  • 18
  • 49
  • 71
lynnyilu
  • 573
  • 1
  • 5
  • 15
  • Can I have a question related to this one: you mean that these code should be put in the LinearLayout, or the EditText that I want to unfocus? Thanks. – detno29 Sep 19 '13 at 03:47
  • You should put it as attribute of the parent view(content view of your activity). You may want to check this out: http://stackoverflow.com/a/19828165/782870 – vida Feb 27 '14 at 14:06
14

Suppose your EditText is placed on Linear layout or other ViewGroup. Then you should make this container clickable, focusable and focusableInTouchMode. After that set onClickListener to this container with following code in onClick Override method:

@Override
public void onClick(View view) {
    InputMethodManager imm = (InputMethodManager) view.getContext()
            .getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Jeff.H
  • 403
  • 4
  • 14
woodshy
  • 4,085
  • 3
  • 22
  • 21
  • 1
    In my case, I am showing a numeric keyboard on focus of the text field. I tried to use your solution. When I click on the background view, the numeric keyboard converts into AlphaNumeric keyboard, then when I click again, it disappears. – Adil Malik Apr 09 '14 at 18:52
  • @AdilMalik, try hiding the keyboard from the edittext's onFocusChangeListener as well – Dmitry Zenovich Sep 30 '18 at 16:58
  • I have the same problem @DmitryZenovich how do I hide the keyboard from the edittexts onfucschangelistener? – Grand Skunk Oct 02 '18 at 07:13
  • @GrandSkunk, you can do that by using the same two lines of code: `InputMethodManager imm = (InputMethodManager) view.getContext() .getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0);` – Dmitry Zenovich Oct 03 '18 at 16:16
3

You can achieve this by doing the following steps:

1.Make the parent view(content view of your activity) clickable and focusable by adding the following attributes

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

2.Implement a hideKeyboard() method

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

3.Lastly, set the onFocusChangeListener of your edittext.

    edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                hideKeyboard(v);
            }
        }
    });
Rajul Goel
  • 31
  • 3
2

The following code works perfectly for me, and I regularly use this for closing the SoftKeyboard onTouch anywhere outside the EditText.

public void hideSoftKeyboard()
{
        //Hides the SoftKeyboard
        InputMethodManager inputMethodManager = (InputMethodManager)  getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
}

public void setupUI(View view) 
{
        String s = "inside";
        //Set up touch listener for non-text box views to hide keyboard.
        if (!(view instanceof EditText)) {

            view.setOnTouchListener(new View.OnTouchListener() {

                public boolean onTouch(View v, MotionEvent event) {
                    hideSoftKeyboard();
                    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);
            }
        }    
}

So you just need to call the setupUI() function once in your onCreate() method and voilla, your hidingSoftKeyboard is setup!

For Losing complete focus of the EditText, simply do editText.clearFocus() in your hideSoftKeyboard() function.

Kaushik NP
  • 6,733
  • 9
  • 31
  • 60
2

Here universal method for all screens. Put it in your activity

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
    clearFocusOnOutsideClick()
    return super.dispatchTouchEvent(ev)
}
/*
* Clear focus on outside click
* */
private fun clearFocusOnOutsideClick() {
    currentFocus?.apply {
        if (this is EditText) {
            clearFocus()
        }
        //Hide keyboard
        val imm: InputMethodManager =
            getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
    }
}

Sergei Maleev
  • 307
  • 3
  • 4
1

So I searched around a little bit, and no other solutions was exactly what I was looking for. In my opinion the focus behave strangely on EditText views.

What I did was...

  1. Make sure the root view is a RelativeLayout

  2. Add an overlay layout that is OVER the area that will make the keyboard disapear, but not the EditText. Something like below:

In my case, the EditText was in a container at the bottom of the screen. so it covered everyhting else.

  1. Have a method that looks a bit like this one :
    private void hideKeyboard() {
        final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
        keyboardOverlay.setVisibility(View.GONE);
        editText.clearFocus();
    }
  1. Now call this method on the onClick of the overlay you created.

  2. What we want now is to make the overlay visible when you press on the editText. You cannot use the onFocus event (at least I did not get it to work...) So what i did is I managed the onTouch event instead.

editText.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(final View v, final MotionEvent event) {
        keyboardOverlay.setVisibility(View.VISIBLE);
        editText.requestFocus();
        return false;
    }
});

The requestFocus() here is to not override the focus event with the onTouch.

Quick advice, when you try this out, you can add a background color to the overlay to see exactly what is happening.

Hope it works for you!

King of Masses
  • 18,405
  • 4
  • 60
  • 77
Charles
  • 317
  • 2
  • 10
0

set in a button or any view: this.getCurrentFocus().clearFocus(); For example:

@Override
public boolean onMenuOpened(int featureId, Menu menu) {
    InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    this.getCurrentFocus().clearFocus();
    return super.onMenuOpened(featureId, menu);
}
nobjta_9x_tq
  • 1,205
  • 14
  • 16
-7

I had the same requirement as I had to hide the keyboard once I touch anywhere outside my EditText box. The setOnFocusChangeListener does not do the job as even if you touch outside the edit text box is still selected.

For this I used the solution edc598 here.

  • I first got the MainLayout containing the whole view and add touch listener to it.
  • When onTouch event was triggered I check if the EditText box has focus.
  • If the EditText box has focus then I check the event's X-Y co-ordinates.
  • Based on the placement of my EditText box I hide the key board if touched anywhere outside the box

Code sample modified from here:

LinearLayout MainLayout = (LinearLayout) findViewById(R.id.MainLayout);
EditText textBox        = (EditText) findViewById(R.id.textBox);   
int X_TOP_LEFT      = 157;
int Y_TOP_LEFT      = 388;
int X_BOTTOM_RIGHT  = 473;
int Y_BOTTOM_RIGHT  = 570;   
MainLayout.setOnTouchListener(new View.OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        if(textBox.isFocused()){

            Log.i("Focussed", "--" + event.getX() + " : " + event.getY() + "--");

            if(event.getX() <= 157 || event.getY() <= 388 || event.getX() >= 473 || event.getY() >= 569){
                //Will only enter this if the EditText already has focus
                //And if a touch event happens outside of the EditText
                textBox.clearFocus();
                InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                //Do something else
            }
        }
        Log.i("X-Y coordinate", "--" + event.getX() + " : " + event.getY() + "--");
    //Toast.makeText(getBaseContext(), "Clicked", Toast.LENGTH_SHORT).show();
        return false;
    }
});
Community
  • 1
  • 1
Sumitk
  • 1,485
  • 6
  • 19
  • 31