每个人都知道要隐藏一个键盘,你需要实现:

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

但这里的大问题是如何隐藏键盘时,用户触摸或选择任何其他地方,不是一个EditText或softKeyboard?

我尝试在我的父活动上使用onTouchEvent(),但只有当用户在任何其他视图之外触摸并且没有滚动视图时才有效。

我试图实现一个触摸,点击,焦点监听器,但没有任何成功。

我甚至尝试实现我自己的滚动视图来拦截触摸事件,但我只能得到事件的坐标,而不是视图被单击。

有标准的方法来做这件事吗?在iPhone中,这非常简单。


当前回答

活动

 @Override
 public boolean dispatchTouchEvent(MotionEvent ev) {
     ScreenUtils.hideKeyboard(this, findViewById(android.R.id.content).getWindowToken());
     return super.dispatchTouchEvent(ev);
 }

ScreenUtils

 public static void hideKeyboard(Context context, IBinder windowToken) {
     InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
     imm.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS);
 }

其他回答

对于这个问题,我有一个简单的解决方案:

InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);

下面的代码片段只是隐藏了键盘:

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

你可以把它放在一个实用工具类中,或者如果你在一个活动中定义它,避免使用活动参数,或者调用hideSoftKeyboard(this)。

最棘手的部分是何时调用它。你可以写一个方法,遍历活动中的每个View,并检查它是否是EditText的实例,如果它没有注册setOnTouchListener到该组件,一切都将到位。如果你想知道如何做到这一点,实际上很简单。这就是你要做的,你写一个像下面这样的递归方法,事实上你可以用它来做任何事情,比如设置自定义字体等…这是方法

public void setupUI(View view) {

    // Set up touch listener for non-text box views to hide keyboard.
    if (!(view instanceof EditText)) {
        view.setOnTouchListener(new OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                hideSoftKeyboard(MyActivity.this);
                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);
        }
    }
}

这就是所有的,只是在你setContentView在你的活动之后调用这个方法。如果你想知道你要传递什么参数,它是父容器的id。给你的父容器分配一个id

<RelativeLayoutPanel android:id="@+id/parent">…< / RelativeLayout >

并调用setupUI(findViewById(R.id.parent)),仅此而已。

如果你想有效地使用它,你可以创建一个扩展的Activity并把这个方法放进去,并让应用程序中的所有其他活动扩展这个Activity并在onCreate()方法中调用它的setupUI()。

如果你使用了多个活动,请定义父布局的公共id <RelativeLayout android:id="@+id/main_parent">…< / RelativeLayout >

然后从Activity中扩展一个类,并在其OnResume()中定义setupUI(findViewById(R.id.main_parent)),并在程序中扩展这个类而不是' ' Activity


下面是上面函数的Kotlin版本:

@file:JvmName("KeyboardUtils")

fun Activity.hideSoftKeyboard() {
    currentFocus?.let {
        val inputMethodManager = ContextCompat.getSystemService(this, InputMethodManager::class.java)!!
        inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0)
    }
}

下面是fje回答的另一个变体,它解决了sosite提出的问题。

这里的思想是在Activity的dispatchTouchEvent方法中处理向下和向上操作。在按下操作时,我们会记录当前聚焦的视图(如果有的话),以及触摸是否在其中,并为以后保存这两个信息。

在向上操作中,我们首先分派,以允许另一个视图潜在地获得焦点。如果在那之后,当前聚焦的视图是最初聚焦的视图,向下触摸在那个视图内,然后我们让键盘打开。

如果当前聚焦视图与最初聚焦视图不同并且它是一个EditText,那么我们也让键盘打开。

否则我们关闭它。

综上所述,其工作原理如下:

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

在任何活动(或扩展类活动)中覆盖公共布尔dispatchTouchEvent(MotionEvent事件)

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    View view = getCurrentFocus();
    boolean ret = super.dispatchTouchEvent(event);

    if (view instanceof EditText) {
        View w = getCurrentFocus();
        int scrcoords[] = new int[2];
        w.getLocationOnScreen(scrcoords);
        float x = event.getRawX() + w.getLeft() - scrcoords[0];
        float y = event.getRawY() + w.getTop() - scrcoords[1];
        
        if (event.getAction() == MotionEvent.ACTION_UP 
 && (x < w.getLeft() || x >= w.getRight() 
 || y < w.getTop() || y > w.getBottom()) ) { 
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0);
        }
    }
 return ret;
}

芬兰湾的科特林版:

 override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        val ret = super.dispatchTouchEvent(ev)
        ev?.let { event ->
            if (event.action == MotionEvent.ACTION_UP) {
                currentFocus?.let { view ->
                    if (view is EditText) {
                        val touchCoordinates = IntArray(2)
                        view.getLocationOnScreen(touchCoordinates)
                        val x: Float = event.rawX + view.getLeft() - touchCoordinates[0]
                        val y: Float = event.rawY + view.getTop() - touchCoordinates[1]
                        //If the touch position is outside the EditText then we hide the keyboard
                        if (x < view.getLeft() || x >= view.getRight() || y < view.getTop() || y > view.getBottom()) {
                            val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                            imm.hideSoftInputFromWindow(view.windowToken, 0)
                            view.clearFocus()
                        }
                    }
                }
            }
        }
        return ret
    }

这就是你需要做的

我有一个解决方案来隐藏键盘:

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

这里在showFlag的位置传递HIDE_IMPLICIT_ONLY,在hiddenFlag的位置传递0。 它会强制关闭软键盘。