Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EditText, clear focus on touch outside

My layout contains ListView, SurfaceView and EditText. When I click on the EditText, it receives focus and the on-screen keyboard pops up. When I click somewhere outside of the EditText, it still has the focus (it shouldn't). I guess I could set up OnTouchListener's on the other views in layout and manually clear the EditText's focus. But seems too hackish...

I also have the same situation in the other layout - list view with different types of items, some of which have EditText's inside. They act just like I wrote above.

The task is to make EditText lose focus when user touches something outside of it.

I've seen similar questions here, but haven't found any solution...

like image 561
note173 Avatar asked Oct 03 '22 21:10

note173


People also ask

How do I clear focus in editText?

It's fine if it worked for you, I solved it with android:focusable="true" android:focusableInTouchMode="true" in the parent RelativeLayout. This answer totally worked for me, removing focus of editText AND closing keyboard.

How do I turn off keyboard focus on Android?

clearFocus() in its touch event listener. This will clear all the focus on any touched textview. Then I proceed to close the soft keyboard on screen.


2 Answers

Building on Ken's answer, here's the most modular copy-and-paste solution.

No XML needed.

Put it in your Activity and it'll apply to all EditTexts including those within fragments within that activity.

@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 );
}
like image 285
zMan Avatar answered Oct 06 '22 10:10

zMan


I tried all these solutions. edc598's was the closest to working, but touch events did not trigger on other Views contained in the layout. In case anyone needs this behavior, this is what I ended up doing:

I created an (invisible) FrameLayout called touchInterceptor as the last View in the layout so that it overlays everything (edit: you also have to use a RelativeLayout as the parent layout and give the touchInterceptor fill_parent attributes). Then I used it to intercept touches and determine if the touch was on top of the EditText or not:

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

Return false to let the touch handling fall through.

It's hacky, but it's the only thing that worked for me.

like image 73
Ken Avatar answered Oct 06 '22 10:10

Ken