How to hide soft keyboard on android after clicking outside EditText?

前端 未结 30 1724
醉话见心
醉话见心 2020-11-22 11:46

Ok everyone knows that to hide a keyboard you need to implement:

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hi         


        
相关标签:
30条回答
  • 2020-11-22 12:29

    I liked the approach of calling dispatchTouchEvent made by htafoya, but:

    • I didn't understand the timer part (don't know why measuring the downtime should be necessary?)
    • I don't like to register/unregister all EditTexts with every view-change (could be quite a lot of viewchanges and edittexts in complex hierarchies)

    So, I made this somewhat easier solution:

    @Override
    public boolean dispatchTouchEvent(final MotionEvent ev) {
        // all touch events close the keyboard before they are processed except EditText instances.
        // if focus is an EditText we need to check, if the touchevent was inside the focus editTexts
        final View currentFocus = getCurrentFocus();
        if (!(currentFocus instanceof EditText) || !isTouchInsideView(ev, currentFocus)) {
            ((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE))
                .hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
        return super.dispatchTouchEvent(ev);
    }
    
    /**
     * determine if the given motionevent is inside the given view.
     * 
     * @param ev
     *            the given view
     * @param currentFocus
     *            the motion event.
     * @return if the given motionevent is inside the given view
     */
    private boolean isTouchInsideView(final MotionEvent ev, final View currentFocus) {
        final int[] loc = new int[2];
        currentFocus.getLocationOnScreen(loc);
        return ev.getRawX() > loc[0] && ev.getRawY() > loc[1] && ev.getRawX() < (loc[0] + currentFocus.getWidth())
            && ev.getRawY() < (loc[1] + currentFocus.getHeight());
    }
    

    There is one disadvantage:

    Switching from one EditText to another EditText makes the keyboard hide and reshow - in my case it's desired that way, because it shows that you switched between two input components.

    0 讨论(0)
  • 2020-11-22 12:30

    I got one more solution to hide the keyboard by:

    InputMethodManager imm = (InputMethodManager) getSystemService(
        Activity.INPUT_METHOD_SERVICE);
    imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
    

    Here pass HIDE_IMPLICIT_ONLY at the position of showFlag and 0 at the position of hiddenFlag. It will forcefully close the soft keyboard.

    0 讨论(0)
  • 2020-11-22 12:30

    I modified the solution of Andre Luis IM I achieved this one:

    I created a utility method to hide the soft keyboard the same way Andre Luiz IM did:

    public static void hideSoftKeyboard(Activity activity) {
        InputMethodManager inputMethodManager = (InputMethodManager)  activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
    }
    

    But instead of register an OnTouchListener for every view, that give a poor performance, I registered the OnTouchListener for just the root view. Since the event bubbles until it's consumed (EditText is one of the views that consumes it by default), if it arrives to the root view, it's because it wasn't consumed, so I close the soft keyboard.

    findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Utils.hideSoftKeyboard(activity);
            return false;
        }
    });
    
    0 讨论(0)
  • 2020-11-22 12:31

    I implemented dispatchTouchEvent in Activity to do this:

    private EditText mEditText;
    private Rect mRect = new Rect();
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final int action = MotionEventCompat.getActionMasked(ev);
    
        int[] location = new int[2];
        mEditText.getLocationOnScreen(location);
        mRect.left = location[0];
        mRect.top = location[1];
        mRect.right = location[0] + mEditText.getWidth();
        mRect.bottom = location[1] + mEditText.getHeight();
    
        int x = (int) ev.getX();
        int y = (int) ev.getY();
    
        if (action == MotionEvent.ACTION_DOWN && !mRect.contains(x, y)) {
            InputMethodManager input = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            input.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
        }
        return super.dispatchTouchEvent(ev);
    }
    

    and I tested it, works perfect!

    0 讨论(0)
  • 2020-11-22 12:31

    I have refined the method, put the following code in some UI utility class(preferably, not necessarily) so that it can be accessed from all your Activity or Fragment classes to serve its purpose.

    public static void serachAndHideSoftKeybordFromView(View view, final Activity act) {
        if(!(view instanceof EditText)) {
            view.setOnTouchListener(new View.OnTouchListener() {
                public boolean onTouch(View v, MotionEvent event) {
                    hideSoftKeyboard(act);
                    return false;
                }
            });
        }
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                View nextViewInHierarchy = ((ViewGroup) view).getChildAt(i);
                serachAndHideSoftKeybordFromView(nextViewInHierarchy, act);
            }
        }
    }
    public static void hideSoftKeyboard (Activity activity) {
        InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
    }
    

    Then say for example you need to call it from activity, call it as follows;

    UIutils.serachAndHideSoftKeybordFromView(findViewById(android.R.id.content), YourActivityName.this);
    

    Notice

    findViewById(android.R.id.content)

    This gives us the root view of the current group(you mustn't have set the id on root view).

    Cheers :)

    0 讨论(0)
  • 2020-11-22 12:32

    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 loosed");
                        // 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

    0 讨论(0)
提交回复
热议问题