Dismiss keyboard when click outside of EditText in android

Viewed 45871

I have an EditText called myTextview. I want the soft keyboard to show when I click on the EditText but then dismiss if I click outside of the EditText. So I use the method below. But the keyboard does not dismiss when I click outside the view (I click a TextView). How do I fix this code?

myTextview.setOnFocusChangeListener(new OnFocusChangeListener() {

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {
                getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
            } else {
                InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(myTextview.getWindowToken(), 0);
            }

        }
    });
9 Answers

Touch event on a View will start with ACTION_DOWN from being passed from top to this View in view hierachy. Override dispatchTouchEvent to do additional things. Here's an example to extend from FrameLayout in kotlin:

class TLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet?=null):
        FrameLayout(context, attrs){

    var preDispatchTouchEvent: ((ev: MotionEvent?)->Boolean)? = null

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        if (preDispatchTouchEvent==null || !preDispatchTouchEvent!!.invoke(ev)) {
            super.dispatchTouchEvent(ev)
        }
        return true
    }

}

Wrap your EditText and other relative Views under this layout, and set preDispatchTouchEvent to dismiss EditText when event is not above it.

Check this OS question and official doc to have deeper understanding of touch event delivering.

I use below Process. It's Working For Me Perfectly. Add below function in your activity Class.

  override fun dispatchTouchEvent(event: MotionEvent): Boolean {
    if (event.action == MotionEvent.ACTION_DOWN) {
        val v = currentFocus
        if (v is EditText) {
            val outRect = Rect()
            v.getGlobalVisibleRect(outRect)
            if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) {
                Log.d("focus", "touchevent")
                v.clearFocus()
                val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.hideSoftInputFromWindow(v.windowToken, 0)
            }
        }
    }
    return super.dispatchTouchEvent(event)
}

Then I will Check Focus status in my fragment.

appCompatEditText.onFocusChangeListener = View.OnFocusChangeListener { view, hasFocus ->
                if (!hasFocus) {
                    toast("Focus Off")
                }else {
                    toast("Focus On")
                }
            }

I was Checked in Fragment. I needed Focus status for my task Requirement. Focus Out I needed some task.

In Kotlin, I have used bellow code which is working fine

override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
    val v = currentFocus
    if (v != null && (ev.action == MotionEvent.ACTION_UP || ev.action == MotionEvent.ACTION_MOVE)
        && v is EditText
        && !v.javaClass.name.startsWith("android.webkit.")
    ) {
        val scrcoords = IntArray(2)
        v.getLocationOnScreen(scrcoords)
        val x = ev.rawX + v.getLeft() - scrcoords[0]
        val y = ev.rawY + v.getTop() - scrcoords[1]
        if (x < v.getLeft() || x > v.getRight() || y < v.getTop() || y > v.getBottom()
        ) hideKeyboard(this)
    }
    return super.dispatchTouchEvent(ev)
}

fun hideKeyboard(activity: Activity?) {
    if (activity != null && activity.window != null && activity.window.decorView != null
    ) {
        val imm = activity
            .getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(
            activity.window.decorView
                .windowToken, 0
        )
    }
}

In Java, I have used bellow code which is working fine

  @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    View v = getCurrentFocus();

    if (v != null
            && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE)
            && v instanceof EditText
            && !v.getClass().getName().startsWith("android.webkit.")) {
        int scrcoords[] = new int[2];
        v.getLocationOnScreen(scrcoords);
        float x = ev.getRawX() + v.getLeft() - scrcoords[0];
        float y = ev.getRawY() + v.getTop() - scrcoords[1];

        if (x < v.getLeft() || x > v.getRight() || y < v.getTop()
                || y > v.getBottom())
            hideKeyboard(this);
    }
    return super.dispatchTouchEvent(ev);
}

public static void hideKeyboard(Activity activity) {
    if (activity != null && activity.getWindow() != null
            && activity.getWindow().getDecorView() != null) {
        InputMethodManager imm = (InputMethodManager) activity
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(activity.getWindow().getDecorView()
                .getWindowToken(), 0);
    }
}
Related