在Android上点击后隐藏默认键盘

16

我想在屏幕上点击编辑框之外的区域时隐藏软键盘。我该怎么做?


它应该自动完成。只要您点击不会弹出键盘本身的任何地方。 - Falmarri
@Falmarri,一开始我以为你是对的,但是在我的测试应用程序中我无法实现这个功能。测试场景:1)点击EditText视图,弹出键盘;2)在同一片段中单击SeekBar;3)单击focusable=true的RadioButton。2和3都没有关闭键盘。这种行为是否有任何建议的文档记录? - Nilzor
10个回答

58

我不得不编辑这个代码才能让它运行。添加了一个检查来判断当前焦点视图是否为EditText。

@Override
public boolean dispatchTouchEvent(MotionEvent event) {

    View v = getCurrentFocus();
    boolean ret = super.dispatchTouchEvent(event);

    if (v 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];

        Log.d("Activity", "Touch event "+event.getRawX()+","+event.getRawY()+" "+x+","+y+" rect "+w.getLeft()+","+w.getTop()+","+w.getRight()+","+w.getBottom()+" coords "+scrcoords[0]+","+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;
}

可能还有更顺畅的方法,但这个方法非常有效。


2
为了更好的解释 - 如果你想在用户点击EditText之外的任何地方关闭键盘,而不仅仅是在另一个按钮的onClick()中,那么Daniel的代码完美地解决了这个问题。只需将该方法添加/覆盖到您的Activity中,用户就可以通过单击EditText之外的任何地方来关闭键盘(对于单个屏幕上的多个EditText也适用)。感谢Daniel! - Kyle Clegg
2
这不是一个完美的答案,因为它会在触摸时隐藏键盘,而不是点击。如果你滚动一下,键盘就会被隐藏。这通常是不想要的。 - User
@Daniel,@kyle Clegg,@lxx,@bibangamba,我正在使用他的代码,它完美地运行,但会导致屏幕闪烁。如果有大约15-20个编辑框,并且您从一个聚焦的编辑框(在输入时)向底部滚动,您将以屏幕闪烁的方式回到相同的位置,因此请帮助我解决这个问题。 - Reprator

32

要强制隐藏键盘,您可以使用以下代码...我将其放在了一个名为“hideSoftKeyboard()”的方法中。 如Falmarri所提到的,软键盘应该在您点击其他位置时自动隐藏。 但是,如果您在另一个项目的“onClick()”中调用此方法,它将强制关闭键盘。

private void hideSoftKeyboard(){
    if(getCurrentFocus()!=null && getCurrentFocus() instanceof EditText){
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(yourEditTextHere.getWindowToken(), 0);
    }
}

7
以下代码可以实现此功能:

1)使用findViewById()将父布局的引用传递到Java代码中。

2)然后将setOnTouchListener()应用于它。

3)在onTouchMethod()中添加以下代码。

 lin = (LinearLayout) findViewById(R.id.lin);
    lin.setOnTouchListener(new OnTouchListener() 
    {
        @Override
        public boolean onTouch(View v, MotionEvent event) 
        {
               InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                               imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0);
                       return false;
        }
    });

6
我将以下内容添加到我的活动中。 它有效,因为点击Focusable View之外不会改变焦点(所以w == v),但触摸将落在该View矩形区域之外。
public boolean dispatchTouchEvent(MotionEvent event) {
    View v = getCurrentFocus();
    boolean ret = super.dispatchTouchEvent(event);
    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];

    Log.d("Activity", "Touch event "+event.getRawX()+","+event.getRawY()+" "+x+","+y+" rect "+w.getLeft()+","+w.getTop()+","+w.getRight()+","+w.getBottom()+" coords "+scrcoords[0]+","+scrcoords[1]);
    if (event.getAction() == MotionEvent.ACTION_UP && (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w.getBottom()) ) { 
        inputManager.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0);
    }
    return ret;

}

[编辑:修复小错误]

1
作为对已接受答案的补充。
如果已接受答案无法解决您的问题,您可以将 hideSoftKeyboard() 方法添加到您的 EditTextonClickListeneronClick() 方法中。例如:
editText.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        hideSoftKeyboard();
    }
});

将上述代码放置在onResume()或其他位置。

附: hideSoftKeyboard()的定义。

private void hideSoftKeyboard(){
    if(getCurrentFocus()!=null && getCurrentFocus() instanceof EditText){
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
    }
}

0

我有一个好的解决方案。我知道现在已经太晚了,但是当搜索时,大多数情况下会将此链接作为第一个链接显示。因此,这可能对其他人有所帮助。如果您单击任何文本/按钮,它将隐藏已经可见的软键盘。

date.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // Hide soft keyboard
       InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
            imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);

      // here i am showing the Date Dialog. one can proceed with their functionality

            //show date picker dialog
            showDialog(Date_DIALOG_ID);
        }
    });

0
public boolean OutsideTouchEvent(MotionEvent m_event) {
    View v = getCurrentFocus();
    boolean value = super.dispatchTouchEvent(m_event);
    View w = getCurrentFocus();
    int scrcoords[] = new int[2];
    w.getLocationOnScreen(scrcoords);
    float x = m_event.getRawX() + w.getLeft() - scrcoords[0];
    float y = m_event.getRawY() + w.getTop() - scrcoords[1];

    if (m_event.getAction() == MotionEvent.ACTION_UP && (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w.getBottom()) ) { 
        InputMethodManager inputMethodManager = (InputMethodManager)  YourActivity.this.getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(YourActivity.this.getCurrentFocus().getWindowToken(), 0);
    }
    return value;

}

0
首先感谢Daniel,他的代码真的很好,我用了一段时间。
最近我意识到我必须改进它。问题出在滚动页面上。我的项目中有很多EditText,当你滚动页面时会隐藏键盘。
我想到了一个解决方案,使用onGestureListener而不是重写dispatchTouchEvent
public class TabActivity extends ActionBarActivity implements GestureDetector.OnGestureListener {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        ...
        gestureScanner = new GestureDetector(TabActivity.this,this);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        gestureScanner.onTouchEvent(ev);
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onSingleTapUp(MotionEvent event) {
        View v = getCurrentFocus();

        if (v instanceof EditText) {
            View w = getCurrentFocus();
            int scrcoords[] = new int[2];
            w.getLocationOnScreen(scrcoords);
            boolean hide = true;

            View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);
            ArrayList<View> editTexts = view.getFocusables(0);     // Get All EditTexts in view

            for(int i=0; i< editTexts.size(); i++){
                View editText = editTexts.get(i);
                editText.getLocationOnScreen(scrcoords);
                float x = event.getRawX();
                float y = event.getRawY();
                int viewX = scrcoords[0];
                int viewY = scrcoords[1];

                // If touch is in any of EditText, keep keyboard active, otherwise hide it.
                if (event.getAction() == MotionEvent.ACTION_UP  && ( x > viewX && x < (viewX + editText.getWidth())) && ( y > viewY && y < (viewY + editText.getHeight())) ) {
                    hide = false;
                }
            }

            if (hide) {
                InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0);
            }
        }
        return true;
    }

    @Override
    public boolean onScroll(MotionEvent event, MotionEvent e2, float distanceX, float distanceY) {
        return true;
    }     
}

因此,如果用户滚动页面,它将进入 onScroll 方法,并且不执行任何操作。如果用户只是触摸屏幕,它会触发 onSingleTapUp 方法。

我还必须更改Daniel代码中的if语句。Daniel正在检查触摸事件是否在EditText之外。由于我有许多EditViews,因此我将代码更改为查找触摸事件是否在任何EditText之内。

对我来说它运作良好,如有任何改进或错误,请告诉我。


View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);我不太明白这句话的意思。你能解释一下吗? - Tara
那是我曾经参与的一个旧项目,我不记得具体细节了。基本上,我的工作就是检索父视图。android.R.id.content将给出根视图。getChildAt(0)可能用于检索我的EditTexts的父级。 - Gokhan Arik
你的意思是在视图组或视图内添加所有编辑文本吗? - Tara
你的情况可能不同。在我的情况下,所有的 EditText 都在一个 LinearLayout 中。所以 view 是我的 LinearLayout,我从这个 LinearLayout 中检索所有的 EditText。你想要实现什么? - Gokhan Arik
在我的情况中,所有的编辑文本都在线性布局中。当我点击提交按钮时,应该隐藏虚拟键盘! - Tara
显示剩余2条评论

0

只需将输入类型设置为 null,就像这样

editText.setInputType(InputType.TYPE_NULL);


0
将输入类型设置为零以供编辑文本使用
editText.setInputType(0);

对我有效果


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