如何在Android上点击EditText外部后隐藏软键盘?

426

大家都知道隐藏键盘需要实现:

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

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

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

我尝试实现了一个触摸、点击、焦点监听器,但都没有成功。

我甚至尝试实现自己的滚动视图来拦截触摸事件,但我只能获得事件的坐标而无法获取所点击的视图。

是否有一种标准方法来解决这个问题?在iPhone上,这真的很容易。


我意识到ScrollView并不是问题所在,而是其中的标签。该视图是一个垂直布局,包含如下内容: TextView、EditText、TextView、EditText等等。而这些TextView会阻止EditText失去焦点并隐藏键盘。 - htafoya
你可以在这里找到 getFields() 的解决方案:https://dev59.com/e2sz5IYBdhLWcg3wlY-9 - Reto
键盘可以通过按回车键来关闭,因此我认为这是否值得努力是有问题的。 - gerrytan
5
我找到了这篇回答:https://dev59.com/7m445IYBdhLWcg3wfKcZ#28939113,是最好的一个。 - Loenix
49个回答

0

对于那些正在寻找Xamarin代码的人,这里有:

  public override bool DispatchTouchEvent(MotionEvent ev)
    {
        try
        {
            View view = CurrentFocus;
            if (view != null && (ev.Action == MotionEventActions.Up || ev.Action == MotionEventActions.Move) && view is EditText && !view.Class.Name.StartsWith("android.webkit."))
            {
                int[] Touch = new int[2];
                view.GetLocationOnScreen(Touch);
                float x = ev.RawX + view.Left - Touch[0];
                float y = ev.RawY + view.Top - Touch[1];
                if (x < view.Left || x > view.Right || y < view.Top || y > view.Bottom)
                    ((InputMethodManager)GetSystemService(InputMethodService)).HideSoftInputFromWindow((Window.DecorView.ApplicationWindowToken), 0);
            }
        }
        catch (System.Exception ex)
        {
           
        }

        return base.DispatchTouchEvent(ev);
    }

0

大家好,我有一个简单的解决方案来解决这个问题,这个解决方案可以用于简单的注册或登录表单。 我的解决方案与我在iOS中实现的相同,将setontouch监听器添加到主视图

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

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

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

你可以使用 "View mainLayout..." 并且能够在不考虑基本布局类型的情况下重复使用它。然而,如果用户点击消耗触摸事件的视图(如按钮和微调控件),你的方法仍然是无效的。 - William T. Mallard

0

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

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

0
我认为这个问题。 首先,我认为setOnTouchListener不是简单的解决方案。 所以我相信dispatchTouchEvent是最好的简单解决方案。
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)上进行了测试。

如果您需要拖动检查、长按等功能,请参见上面的注释。


0

我有一个简单的解决方案:

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

0
另一个想法是在您的活动的根视图上重写onInterceptTouchEvent方法。
触摸事件从屏幕上最前面的视图(触摸事件发生的地方)向下传递到视图堆栈,调用onTouch方法,直到任何一个视图返回true,表示触摸事件已被消耗。由于许多视图默认情况下会消耗触摸事件(例如EditTextTextView),因此该事件不会到达Activity的根视图onTouch方法。
但是,在执行此遍历之前,触摸事件会沿着另一条路径移动,从根视图向下遍历视图树,直到到达最前面的视图。这个遍历是通过调用onInterceptTouchEvent完成的。如果该方法返回true,则会拦截事件...嗯,但这有点棘手,我不认为您想这样做或知道细节。您需要知道的是,您可以在您的活动的根视图上覆盖此方法,并在那里放置必要时隐藏键盘的代码。

我几个小时前就想到了这个问题,但我的问题是如何知道事件的坐标是否属于EditText或键盘。换句话说,如何根据坐标获取视图,因为我只想使用instanceof EditText,我试图避免在每个类上实现此方法并比较特定对象边界。 - htafoya
无论如何,我喜欢你的问题。我可能会在我正在处理的一个项目中遇到同样的问题,而这个问题已经产生了一些好的想法。如果我在解决问题时有更好的解决方案,我会在这里发布。 - Andre Luis IM

0

我成功地在onItemClick AutoCompleteTextView内部隐藏了键盘。

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
}

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

将该方法传递到您的布局文件中。您必须在XML中选择您的常用布局文件。 因为键盘隐藏与整个布局一起工作。

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

由于您引用了特定类LOGSignUpActivity.this,使得代码仅适用于此活动,因此翻译后的内容与接受的答案相同但更差。 - Gustavo Baiocchi Costa

-1

前往清单并在活动中编写:android:windowSoftInputMode="stateHidden",就像这样

<activity
   android:name=".MainActivity"
   android:exported="false"
   android:windowSoftInputMode="stateHidden" />

1
答案对我不起作用。在Android 12中进行了测试。 - Shunan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接