如何在EditText外单击后在android上隐藏软键盘?

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

好的,大家都知道要隐藏你需要实现的键盘:

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

但这里最重要的是当用户触摸或选择不是EditText或softKeyboard的任何其他地方时如何隐藏键盘?

我试图在我的父Activity上使用onTouchEvent(),但这只有在用户触摸任何其他视图以外且没有scrollview时才有效。

我尝试实现触摸,单击,集中监听器而没有任何成功。

我甚至尝试实现自己的scrollview来拦截触摸事件,但我只能获取事件的坐标而不是点击的视图。

有没有一种标准的方法来做到这一点? 在iPhone中它真的很容易。


以下代码段只是隐藏了键盘:

1
2
3
4
5
6
7
public static void hideSoftKeyboard(Activity activity) {
    InputMethodManager inputMethodManager =
        (InputMethodManager) activity.getSystemService(
            Activity.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow(
        activity.getCurrentFocus().getWindowToken(), 0);
}

您可以将其放在实用程序类中,或者如果要在活动中定义它,请避免使用activity参数,或调用hideSoftKeyboard(this)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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分配给父容器,如

...

并调用setupUI(findViewById(R.id.parent)),就是这样。

如果要有效地使用它,可以创建扩展Activity并将此方法放入,并使应用程序中的所有其他活动扩展此活动并在onCreate()方法中调用其setupUI()

希望能帮助到你。

如果您使用多个活动,则将父公布定义为公共ID
...

然后从Activity扩展一个类并在其OnResume()中定义setupUI(findViewById(R.id.main_parent))并扩展此类而不是``Activity in your program


您可以通过执行以下步骤来实现此目的:

  • 通过添加以下属性,使父视图(活动的内容视图)可单击并可聚焦

    1
    2
        android:clickable="true"
        android:focusableInTouchMode="true"
  • 实现hideKeyboard()方法

    1
    2
    3
    4
        public void hideKeyboard(View view) {
            InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
  • 最后,设置edittext的onFocusChangeListener。

    1
    2
    3
    4
    5
    6
    7
    8
        edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus) {
                    hideKeyboard(v);
                }
            }
        });
  • 正如下面的一条评论中所指出的,如果父视图是ScrollView,这可能不起作用。对于这种情况,可以在ScrollView正下方的视图上添加clickable和focusableInTouchMode。


    我发现接受的答案有点复杂。

    这是我的解决方案。在主布局中添加OnTouchListener,即:

    1
    findViewById(R.id.mainLayout).setOnTouchListener(this)

    并将以下代码放在onTouch方法中。

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

    这样您就不必遍历所有视图。


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

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

    这里showFlag位于showFlag0位置HIDE_IMPLICIT_ONLY
    它将强制关闭软键盘。


    只需覆盖Activity中的以下代码即可

    1
    2
    3
    4
    5
    6
    7
    8
     @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);
    }


    好吧我设法解决了这个问题,我在我的活动上覆盖了dispatchTouchEvent,在那里我使用以下来隐藏键盘。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     /**
     * Called to process touch screen events.
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                touchDownTime = SystemClock.elapsedRealtime();
                break;

            case MotionEvent.ACTION_UP:
                //to avoid drag events
                if (SystemClock.elapsedRealtime() - touchDownTime <= 150){  

                    EditText[] textFields = this.getFields();
                    if(textFields != null && textFields.length > 0){

                        boolean clickIsOutsideEditTexts = true;

                        for(EditText field : textFields){
                            if(isPointInsideView(ev.getRawX(), ev.getRawY(), field)){
                                clickIsOutsideEditTexts = false;
                                break;
                            }
                        }

                        if(clickIsOutsideEditTexts){
                            this.hideSoftKeyboard();
                        }              
                    } else {
                        this.hideSoftKeyboard();
                    }
                }
                break;
        }

        return super.dispatchTouchEvent(ev);
    }

    编辑:getFields()方法只是一个返回视图中包含文本字段的数组的方法。为了避免在每次触摸时创建这个数组,我创建了一个名为sFields的静态数组,它在getFields()方法中返回。此数组在onStart()方法上初始化,例如:

    sFields = new EditText[] {mUserField, mPasswordField};

    它并不完美,拖动事件时间只是基于启发式,所以有时它在执行长文件时不会隐藏,我还完成了创建一个方法来获取每个视图的所有editTexts;否则键盘会在单击其他EditText时隐藏和显示。

    仍然,欢迎更清洁和更短的解决方案


    使用OnFocusChangeListener。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                hideKeyboard();
            }
        }
    });

    更新:您还可以覆盖活动中的onTouchEvent()并检查触摸的坐标。如果坐标在EditText之外,则隐藏键盘。


    我在Activity中实现了dispatchTouchEvent来执行此操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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);
    }

    我测试了它,效果很好!


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @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;
    }

    这就是你需要做的一切


    更多Kotlin&amp;使用TextInputEditText的Material Design方式(这种方法也与EditTextView兼容)......

    1.通过添加以下属性,使父视图(活动/片段的内容视图)可单击并可聚焦

    1
    2
    3
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:clickable="true"

    2.为所有View创建扩展(例如,在ViewExtension.kt文件中):

    1
    2
    3
    4
    fun View.hideKeyboard(){
        val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
        inputMethodManager.hideSoftInputFromWindow(this.windowToken, 0)
    }

    3.创建继承TextInputEditText的BaseTextInputEditText。在视图未聚焦时,实现onFocusChanged方法隐藏键盘:

    1
    2
    3
    4
    5
    6
    class BaseTextInputEditText(context: Context?, attrs: AttributeSet?) : TextInputEditText(context, attrs){
        override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
            super.onFocusChanged(focused, direction, previouslyFocusedRect)
            if (!focused) this.hideKeyboard()
        }
    }

    4.只需在XML中调用全新的自定义视图:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <android.support.design.widget.TextInputLayout
            android:id="@+id/textInputLayout"
            ...>

            <com.your_package.BaseTextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                ... />

        </android.support.design.widget.TextInputLayout>

    就这样。无需修改控制器(片段或活动)来处理这种重复的情况。


    我知道这个线程已经很老了,正确的答案似乎是有效的,并且有很多工作解决方案,但我认为下面提出的方法可能会在效率和优雅方面带来额外的好处。

    我的所有活动都需要这种行为,所以我创建了一个继承自Activity类的CustomActivity类,并"挂钩"了dispatchTouchEvent函数。主要有两个条件需要照顾:

  • 如果焦点未更改且有人在当前输入字段之外点击,则关闭IME
  • 如果焦点已更改且下一个焦点元素不是任何类型的输入字段的实例,则忽略IME
  • 这是我的结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    @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);
    }

    旁注:此外,我将这些属性分配给根视图,从而可以清除对每个输入字段的关注,并防止输入字段聚焦于活动启动(使内容视图成为"焦点捕获器"):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final View view = findViewById(R.id.content);

        view.setFocusable(true);
        view.setFocusableInTouchMode(true);
    }


    我修改了Andre Luis IM的解决方案我实现了这个:

    我创建了一个实用工具方法来隐藏软键盘,就像Andre Luiz IM所做的那样:

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

    但是,不是为每个视图注册一个OnTouchListener,而是性能很差,我只为root视图注册了OnTouchListener。由于事件一直消耗直到被消耗(EditText是默认使用它的视图之一),如果它到达根视图,那是因为它没有被消耗,所以我关闭了软键盘。

    1
    2
    3
    4
    5
    6
    7
    findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Utils.hideSoftKeyboard(activity);
            return false;
        }
    });


    我喜欢调用htafoya制作的dispatchTouchEvent的方法,但是:

    • 我不明白计时器部分(不知道为什么要测量停机时间?)
    • 我不喜欢在每次视图更改时注册/取消注册所有EditTexts(在复杂的层次结构中可能有很多视图更改和edittexts)

    所以,我做了一些更简单的解决方案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    @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());
    }

    有一个缺点:

    从一个EditText切换到另一个EditText使键盘隐藏和重新显示 - 在我的情况下,它需要这样,因为它显示您在两个输入组件之间切换。


    辩诉:我知道我没有影响力,但请认真对待我的回答。

    问题:单击远离键盘或使用最少代码编辑文本时,关闭软键盘。

    解决方案:外部库称为Butterknife。

    单线解决方案:

    1
    @OnClick(R.id.activity_signup_layout) public void closeKeyboard() { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }

    更易读的解决方案:

    1
    2
    3
    4
    5
    @OnClick(R.id.activity_signup_layout)
    public void closeKeyboard() {
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    }

    说明:将OnClick侦听器绑定到活动的XML布局父ID,以便对布局(而不是编辑文本或键盘)上的任何单击都将运行将隐藏键盘的代码片段。

    示例:如果您的布局文件是R.layout.my_layout,并且您的布局ID是R.id.my_layout_id,那么您的Butterknife绑定调用应该如下所示:

    1
    2
    3
    4
    5
    (@OnClick(R.id.my_layout_id)
    public void yourMethod {
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    }

    Butterknife文档链接:http://jakewharton.github.io/butterknife/

    插件:Butterknife将彻底改变您的Android开发。考虑一下。

    注意:如果不使用外部库Butterknife,可以获得相同的结果。只需将OnClickListener设置为父布局,如上所述。


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

    这里的想法是处理Activity的dispatchTouchEvent方法中的向下和向上操作。在向下动作中,我们记下当前聚焦的视图(如果有的话)以及触摸是否在其中,保存这些信息以供稍后使用。

    在up动作中,我们首先发送,以允许另一个视图可能成为焦点。如果在此之后,当前聚焦的视图是最初聚焦的视图,并且向下触摸在该视图内,则我们使键盘保持打开状态。

    如果当前聚焦的视图与最初聚焦的视图不同并且它是EditText,那么我们也将键盘保持打开状态。

    否则我们关闭它。

    总而言之,这可以如下工作:

    • 当触摸当前聚焦的EditText内部时,键盘保持打开状态
    • 当从焦点EditText移动到另一个EditText时,键盘保持打开状态(不关闭/重新打开)
    • 当触摸当前聚焦的EditText(不是另一个EditText)之外的任何地方时,键盘关闭
    • 当长按EditText以调出上下文操作栏(使用剪切/复制/粘贴按钮)时,键盘保持打开状态,即使UP操作发生在聚焦EditText之外(向下移动到为CAB腾出空间)。但请注意,当您点击CAB中的按钮时,它将关闭键盘。这可能是也可能不是可取的;如果你想从一个字段剪切/复制并粘贴到另一个字段,那就是。如果要粘贴回相同的EditText,则不会。
    • 当焦点EditText位于屏幕底部并且您长按某些文本以选择它时,EditText保持焦点,因此键盘会按照您的需要打开,因为我们执行"触摸在视图范围内""检查下行动,而不是上行动。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      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);
      }

    它过于简单,只需通过以下代码使您最近的布局可点击:

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

    然后为该布局编写一个方法和一个OnClickListner,这样当触摸最上面的布局时,它会调用一个方法,在这个方法中你将编写代码来解除键盘。以下是两者的代码;
    //你必须在OnCreate()中写这个

    1
    2
    3
    4
    5
    6
     yourLayout.setOnClickListener(new View.OnClickListener(){
                    @Override
                    public void onClick(View view) {
                        hideKeyboard(view);
                    }
                });

    从listner调用的方法: -

    1
    2
    3
    4
     public void hideKeyboard(View view) {
         InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }

    对于这个简单的要求,我发现接受的答案有点复杂。这对我来说没有任何故障。

    1
    2
    3
    4
    5
    6
    7
    8
    findViewById(R.id.mainLayout).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
                return false;
            }
        });


    显示/隐藏软键盘的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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);    
            }

        }

    我希望他们有用


    我已经改进了方法,将以下代码放在一些UI实用程序类中(最好不一定),以便可以从所有Activity或Fragment类访问它以实现其目的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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);
    }

    然后说例如你需要从活动中调用它,如下调用它;

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

    注意

    findViewById(android.R.id.content)

    这为我们提供了当前组的根视图(您不能在根视图上设置id)。

    干杯:)


    有一种更简单的方法,基于iPhone同样的问题。只需覆盖触摸事件的背景布局,其中包含编辑文本。只需在活动的OnCreate中使用此代码(login_fondo是根布局):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        final LinearLayout llLogin = (LinearLayout)findViewById(R.id.login_fondo);
        llLogin.setOnTouchListener(
                new OnTouchListener()
                {
                    @Override
                    public boolean onTouch(View view, MotionEvent ev) {
                        InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(
                                android.content.Context.INPUT_METHOD_SERVICE);
                        imm.hideSoftInputFromWindow(mActivity.getCurrentFocus().getWindowToken(), 0);
                        return false;
                    }
                });


    在kotlin,我们可以做到以下几点。无需迭代所有视图。它也适用于碎片。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        currentFocus?.let {
            val imm: InputMethodManager = getSystemService(
                Context.INPUT_METHOD_SERVICE
            ) as (InputMethodManager)
            imm.hideSoftInputFromWindow(it.windowToken, 0)
        }
        return super.dispatchTouchEvent(ev)
    }

    尝试将stateHidden设置为您的活动windowSoftInputMode

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

    例如,对于您的活动:

    1
    2
    this.getWindow().setSoftInputMode(
        WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

    这是fje的答案的略微修改版本,大部分都很完美。

    此版本使用ACTION_DOWN,因此执行滚动操作也会关闭键盘。
    除非您单击另一个EditText,否则它也不会传播该事件。这意味着单击EditText外的任何位置,即使是另一个可单击的,也只需关闭键盘即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
        if(ev.getAction() == MotionEvent.ACTION_DOWN)
        {
            final View view = getCurrentFocus();

            if(view != null)
            {
                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))
                    {
                        super.dispatchTouchEvent(ev);
                        return true;
                    }
                }
                else if(viewNew instanceof EditText || viewNew instanceof CustomEditText)
                {
                    super.dispatchTouchEvent(ev);
                    return true;
                }

                final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

                inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0);

                viewNew.clearFocus();

                return true;
            }
        }
        return super.dispatchTouchEvent(ev);
    }


    1
    2
    3
    4
    5
    6
    7
    @Override
        public boolean onTouchEvent(MotionEvent event) {
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.
                    INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
            return true;
        }


    只需在课程中添加此代码即可
    @Overide

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public boolean dispatchTouchEvent(MotionEvent ev) {
        View view = getCurrentFocus();
        if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) {
            int scrcoords[] = new int[2];
            view.getLocationOnScreen(scrcoords);
            float x = ev.getRawX() + view.getLeft() - scrcoords[0];
            float y = ev.getRawY() + view.getTop() - scrcoords[1];
            if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom())
                ((InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((this.getWindow().getDecorView().getApplicationWindowToken()), 0);
        }
        return super.dispatchTouchEvent(ev);
    }


    我这样做了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
       View view = getCurrentFocus();
       if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) {
                int scrcoords[] = new int[2];
                view.getLocationOnScreen(scrcoords);
                float x = ev.getRawX() + view.getLeft() - scrcoords[0];
                float y = ev.getRawY() + view.getTop() - scrcoords[1];
                if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom())
                    hideKeyboard(this);
            }
        return super.dispatchTouchEvent(ev);
    }

    隐藏键盘代码:

    1
    2
    3
    4
    public static void hideKeyboard(Activity act) {
        if(act!=null)
          ((InputMethodManager)act.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((act.getWindow().getDecorView().getApplicationWindowToken()), 0);
      }

    完成


    要解决此问题,您需要首先使用该Edittext的setOnFocusChangeListener

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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");
                    }
                }
            });

    然后你需要做的是覆盖包含Edittext的活动中的dispatchTouchEvent,见下面的代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @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);
    }

    现在会发生什么事情,当用户点击外面然后首先调用dispatchTouchEvent然后将从editext清除焦点现在你的OnFocusChangeListener将被调用焦点已被更改现在你可以做任何你想做的事情希望它工作


    活动

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

    ScreenUtils

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


    这可能是旧的但我通过实现自定义类来实现这一点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class DismissKeyboardListener implements OnClickListener {

        Activity mAct;

        public DismissKeyboardListener(Activity act) {
            this.mAct = act;
        }

        @Override
        public void onClick(View v) {
            if ( v instanceof ViewGroup ) {
                hideSoftKeyboard( this.mAct );
            }
        }      
    }

    public void hideSoftKeyboard(Activity activity) {
            InputMethodManager imm = (InputMethodManager)
            getSystemService(Activity.INPUT_METHOD_SERVICE);
            imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
    }

    这里的最佳实践是创建一个Helper类,每个容器相对/线性布局都应该实现这一点。

    ****请注意只有主要容器应该实现这个类(用于优化)****

    并像这样实现它:

    1
    Parent.setOnClickListener( new DismissKeyboardListener(this) );

    关键字this是Activity。所以,如果你是片段,你使用像getActivity();

    ---如果对你帮助大拇指......
    ---欢呼拉尔夫---


    那么,您可以使用此代码,使用您的主要布局ID而不是"mainRelativeLayout"

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //hide Soft keyboard on click outside  the input text
        findViewById(R.id.mainRelativeLayout).setOnClickListener(new
    View.OnClickListener() {
            @Override
            public void onClick(View v) {
                InputMethodManager im = (InputMethodManager)
    getSystemService(INPUT_METHOD_SERVICE);
                im.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
    0);
            }

        });


    其他想法是在Activity的根视图上覆盖onInterceptTouchEvent方法。

    触摸事件从屏幕上的最前面视图(发生触摸事件的位置)向下调用onTouch方法的视图堆栈,直到任何视图返回true,表示触摸事件已被消耗。由于许多视图默认使用触摸事件(例如,EditTextTextView的情况),因此事件无法访问Activity的根View onTouch方法。

    但是,在进行此遍历之前,触摸事件会沿着另一条路径行进,从根视图向下看到视图树,直到它到达最前面的视图。通过调用onInterceptTouchEvent完成此遍历。如果方法返回true,它会拦截事件...... nahhh,但这有点诡计,我认为你不想这样做也不知道细节。您需要知道的是,您可以在Activity的根视图上覆盖此方法,并在必要时放置代码以隐藏键盘。


    这个对我来说是最简单的解决方案(由我来解决)。

    这是隐藏键盘的方法。

    1
    2
    3
    4
    5
    6
    public void hideKeyboard(View view){
            if(!(view instanceof EditText)){
                InputMethodManager inputMethodManager=(InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
                inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
            }
        }

    现在,将活动的父布局的onclick属性设置为上面的方法hideKeyboard,或者从XML文件的"设计"视图中设置,或者在XML文件的"文本"视图中的代码下面写入。

    1
    android:onClick="hideKeyboard"

    我设法隐藏了onItemClick AutoCompleteTextView内的键盘

    1
    2
    3
    4
    5
    public void onItemClick(AdapterView< ? > adapterViewIn, View viewIn, int indexSelected, long arg3) {
         InputMethodManager imm = (InputMethodManager) getSystemService(viewIn.getContext().INPUT_METHOD_SERVICE);
         imm.hideSoftInputFromWindow(viewIn.getApplicationWindowToken(), 0);
         // your code HERE
    }

    我以为这个问题。
    首先,我认为setOnTouchListener不是简单的解决方案。
    所以我相信dispatchTouchEvent是最简单的解决方案。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            View v = getCurrentFocus();
            if (v instanceof EditText) {
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
            }
        }
        return super.dispatchKeyEvent(event);
    }

    在这里,一个重要的是ACTION_UP。

    我假设EditText只显示软键盘,否则不显示键盘。
    我在Android5.0.1(LG的G3.cat6)上测试过。

    如果你需要拖动检查,长按,...,显示上面的评论。


    我在Fernando Camarago的解决方案上略微改变了这一点。在我的onCreate方法中,我将一个onTouchListener附加到根视图,但是将视图而不是活动作为参数发送。

    1
    2
    3
    4
    5
    6
            findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {          
            public boolean onTouch(View v, MotionEvent event) {
                Utils.hideSoftKeyboard(v);
                return false;
            }
        });

    在一个单独的Utils类中......

    1
    2
    3
    4
        public static void hideSoftKeyboard(View v) {
        InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
    }

    你可以尝试下面的方式,它对我很有用:)

    这种方式可以应用于Activity或Fragment,它也与ScrollView兼容。

    我们将ScrollView作为顶级布局,为内部的LinearLayout声明id parentView,并添加如下两个属性:

    1
    2
    3
    android:id="@+id/parentView"
    android:clickable="true"
    android:focusableInTouchMode="true"

    在代码中,编写如下函数:

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

    然后为根视图注册OnFocusChangeListener(在onCreate方法中写入)以使Activity中的所有EditText受到影响:

    1
    2
    3
    4
    5
    6
    7
    8
    parentLayout.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    if (hasFocus) {
                        hideSoftKeyboard(your_activity_name.this);
                    }
                }
            });

    我的解决方案在所有编辑文本的任何活动中隐藏键盘外部点击。没有逐一指定它们。

    首先添加布局xml的根视图:
    机器人:可点击="真"
    机器人:focusableInTouchMode ="真"

    接下来,创建一个要隐藏键盘的所有活动的父级Acitvity,并指定onResume()方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     @Override
        protected void onResume() {
            super.onResume();
            //getting Root View that gets focus
            View rootView =((ViewGroup)findViewById(android.R.id.content)).
                    getChildAt(0);
            rootView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    if (hasFocus) {
                        hideKeyboard(AbstractActivity.this);
                    }
                }
            });
        }

    使用此常规活动(继承功能!)扩展您的活动,这就是所有,每当任何EditText(在任何扩展活动上)失去焦点时,键盘都将被隐藏。

    附: hideKeyboard方法:

    1
    2
    3
    4
    public static void hideKeyboard(Activity context) {
        InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow( context.getCurrentFocus().getWindowToken(), 0);
    }

    context.getCurrentFocus()不需要指定特定的EditText视图。


    您可以轻松覆盖活动和片段中的onKey()事件以隐藏键盘。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (keyCode == event.KEYCODE_ENTER) {

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

                return true;
            }
        }
        return false;
    }

    嘿家伙我有这个问题的简单解决方案,这个解决方案可以用于简单的注册或登录表单。
    我的解决方案与我在ios setontouch监听器中实现的主视图相同

    activity_main.xml将ID添加到主相对布局android:id="@+id/mainlayout"

    并将此代码添加到您的活动中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      RelativeLayout mainLayout = (RelativeLayout)findViewById(R.id.mainlayout);
      mainLayout.setOnTouchListener(new OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    // TODO Auto-generated method stub
                     Log.d("Json Response","Touch outside");
                      InputMethodManager inputMethodManager = (InputMethodManager)  MainActivity.this.getSystemService(Activity.INPUT_METHOD_SERVICE);
                        inputMethodManager.hideSoftInputFromWindow(MainActivity.this.getCurrentFocus().getWindowToken(), 0);
                    return false;
                }
            });


    1
    setupUI((RelativeLayout) findViewById(R.id.activity_logsign_up_RelativeLayout));

    将方法传递到布局文件中。您必须以XML格式选择公共布局文件。
    因为,键盘隐藏适用于整个布局。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public void setupUI(View view) {
            // Set up touch listener for non-text box views to hide keyboard.
            if (!(view instanceof EditText)) {
                view.setOnTouchListener(new View.OnTouchListener() {
                    public boolean onTouch(View v, MotionEvent event) {
                        hideSoftKeyboard(Your Context); // Pass your context
                        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);
                }
            }
        }