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

前端 未结 30 1721
醉话见心
醉话见心 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:06

    Just override below code in Activity

     @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (getCurrentFocus() != null) {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        }
        return super.dispatchTouchEvent(ev);
    }
    
    0 讨论(0)
  • 2020-11-22 12:06

    I'm aware that this thread is quite old, the correct answer seems valid and there are a lot of working solutions out there, but I think the approach stated bellow might have an additional benefit regarding efficiency and elegance.

    I need this behavior for all of my activities, so I created a class CustomActivity inheriting from the class Activity and "hooked" the dispatchTouchEvent function. There are mainly two conditions to take care of:

    1. If focus is unchanged and someone is tapping outside of the current input field, then dismiss the IME
    2. If focus has changed and the next focused element isn't an instance of any kind of an input field, then dismiss the IME

    This is my result:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(ev.getAction() == MotionEvent.ACTION_UP) {
            final View view = getCurrentFocus();
    
            if(view != null) {
                final boolean consumed = super.dispatchTouchEvent(ev);
    
                final View viewTmp = getCurrentFocus();
                final View viewNew = viewTmp != null ? viewTmp : view;
    
                if(viewNew.equals(view)) {
                    final Rect rect = new Rect();
                    final int[] coordinates = new int[2];
    
                    view.getLocationOnScreen(coordinates);
    
                    rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight());
    
                    final int x = (int) ev.getX();
                    final int y = (int) ev.getY();
    
                    if(rect.contains(x, y)) {
                        return consumed;
                    }
                }
                else if(viewNew instanceof EditText || viewNew instanceof CustomEditText) {
                    return consumed;
                }
    
                final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    
                inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0);
    
                viewNew.clearFocus();
    
                return consumed;
            }
        }       
    
        return super.dispatchTouchEvent(ev);
    }
    

    Side note: Additionally I assign these attributes to the root view making it possible to clear focus on every input field and preventing input fields gaining focus on activity startup (making the content view the "focus catcher"):

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        final View view = findViewById(R.id.content);
    
        view.setFocusable(true);
        view.setFocusableInTouchMode(true);
    }
    
    0 讨论(0)
  • 2020-11-22 12:08

    its too simple, just make your recent layout clickable an focusable by this code:

    android:id="@+id/loginParentLayout"
    android:clickable="true"
    android:focusableInTouchMode="true"
    

    and then write a method and an OnClickListner for that layout , so that when the uppermost layout is touched any where it will call a method in which you will write code to dismiss keyboard. following is the code for both; // you have to write this in OnCreate()

     yourLayout.setOnClickListener(new View.OnClickListener(){
                    @Override
                    public void onClick(View view) {
                        hideKeyboard(view);
                    }
                });
    

    method called from listner:-

     public void hideKeyboard(View view) {
         InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    
    0 讨论(0)
  • 2020-11-22 12:10

    Here's another variation on fje's answer that addresses the issues raised by sosite.

    The idea here is to handle both the down and the up actions in the Activity's dispatchTouchEvent method. On the down action, we make note of the currently focused view (if any) and whether the touch was inside it, saving both those bits of info for later.

    On the up action, we first dispatch, to allow another view to potentially take focus. If after that, the currently focused view is the originally focused view, and the down touch was inside that view, then we leave the keyboard open.

    If the currently focused view is different than the originally focused view and it's an EditText, then we also leave the keyboard open.

    Otherwise we close it.

    So, to sum up, this works as follows:

    • when touching inside a currently focused EditText, the keyboard stays open
    • when moving from a focused EditText to another EditText, the keyboard stays open (doesn't close/reopen)
    • when touching anywhere outside a currently focused EditText that is not another EditText, the keyboard closes
    • when long-pressing in an EditText to bring up the contextual action bar (with the cut/copy/paste buttons), the keyboard stays open, even though the UP action took place outside the focused EditText (which moved down to make room for the CAB). Note, though, that when you tap on a button in the CAB, it will close the keyboard. That may or may not be desirable; if you want to cut/copy from one field and paste to another, it would be. If you want to paste back into the same EditText, it would not be.
    • when the focused EditText is at the bottom of the screen and you long-click on some text to select it, the EditText keeps focus and therefore the keyboard opens like you want, because we do the "touch is within view bounds" check on the down action, not the up action.

      private View focusedViewOnActionDown;
      private boolean touchWasInsideFocusedView;
      
      
      @Override
      public boolean dispatchTouchEvent(MotionEvent ev) {
          switch (ev.getAction()) {
              case MotionEvent.ACTION_DOWN:
                  focusedViewOnActionDown = getCurrentFocus();
                  if (focusedViewOnActionDown != null) {
                      final Rect rect = new Rect();
                      final int[] coordinates = new int[2];
      
                      focusedViewOnActionDown.getLocationOnScreen(coordinates);
      
                      rect.set(coordinates[0], coordinates[1],
                              coordinates[0] + focusedViewOnActionDown.getWidth(),
                              coordinates[1] + focusedViewOnActionDown.getHeight());
      
                      final int x = (int) ev.getX();
                      final int y = (int) ev.getY();
      
                      touchWasInsideFocusedView = rect.contains(x, y);
                  }
                  break;
      
              case MotionEvent.ACTION_UP:
      
                  if (focusedViewOnActionDown != null) {
                      // dispatch to allow new view to (potentially) take focus
                      final boolean consumed = super.dispatchTouchEvent(ev);
      
                      final View currentFocus = getCurrentFocus();
      
                      // if the focus is still on the original view and the touch was inside that view,
                      // leave the keyboard open.  Otherwise, if the focus is now on another view and that view
                      // is an EditText, also leave the keyboard open.
                      if (currentFocus.equals(focusedViewOnActionDown)) {
                          if (touchWasInsideFocusedView) {
                              return consumed;
                          }
                      } else if (currentFocus instanceof EditText) {
                          return consumed;
                      }
      
                      // the touch was outside the originally focused view and not inside another EditText,
                      // so close the keyboard
                      InputMethodManager inputMethodManager =
                              (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                      inputMethodManager.hideSoftInputFromWindow(
                          focusedViewOnActionDown.getWindowToken(), 0);
                      focusedViewOnActionDown.clearFocus();
      
                      return consumed;
                  }
                  break;
          }
      
          return super.dispatchTouchEvent(ev);
      }
      
    0 讨论(0)
  • 2020-11-22 12:10

    Try to put stateHidden on as your activity windowSoftInputMode value

    http://developer.android.com/reference/android/R.attr.html#windowSoftInputMode

    For example for your Activity:

    this.getWindow().setSoftInputMode(
        WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
    
    0 讨论(0)
  • 2020-11-22 12:11

    Method for show / hide soft keyboard

    InputMethodManager inputMethodManager = (InputMethodManager) currentActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (isShow) {
            if (currentActivity.getCurrentFocus() == null) {
                inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
            } else {
                inputMethodManager.showSoftInput(currentActivity.getCurrentFocus(), InputMethodManager.SHOW_FORCED);    
            }
    
        } else {
            if (currentActivity.getCurrentFocus() == null) {
                inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);
            } else {
                inputMethodManager.hideSoftInputFromInputMethod(currentActivity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);    
            }
    
        }
    

    I hope they have been useful

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