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

时间:2010-11-12 14:04:10

标签: android android-softkeyboard

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

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

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

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

我尝试实现触摸,点击,关注监听器而没有任何成功。

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

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

45 个答案:

答案 0 :(得分:540)

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

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,那么一切都将落实到位。如果你想知道如何做到这一点,事实上它很简单。这是你做的,你写一个像下面这样的递归方法,实际上你可以用它来做任何事情,比如设置自定义字体等......这是方法

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并将此方法放入其中,并使您的应用程序中的所有其他活动扩展此活动并在{{setupUI()中调用它1}}方法。

希望它有所帮助。

如果您使用多于1个活动,则将父公司布局定义为公共ID onCreate()

然后从<RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>扩展一个类并在其Activity中定义setupUI(findViewById(R.id.main_parent))并扩展此类而不是“活动OnResume()

答案 1 :(得分:249)

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

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

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

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

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

答案 2 :(得分:54)

我觉得接受的答案有点复杂。

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

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

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

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

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

答案 3 :(得分:37)

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

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

此处HIDE_IMPLICIT_ONLY位于showFlag0位置hiddenFlag。 它会强行关闭软键盘。

答案 4 :(得分:16)

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

 /**
 * 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};


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

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

答案 5 :(得分:13)

使用OnFocusChangeListener

例如:

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
            hideKeyboard();
        }
    }
});

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

答案 6 :(得分:12)

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

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

我测试了它,效果很好!

答案 7 :(得分:11)

在任何Activity(或扩展Activity类)中覆盖公共布尔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;
}

这就是你需要做的一切

答案 8 :(得分:10)

只需覆盖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);
}

答案 9 :(得分:8)

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

我的所有活动都需要这种行为,所以我创建了一个继承自 Activity 类的 CustomActivity ,并“挂钩” dispatchTouchEvent 功能。主要有两个条件需要处理:

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

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

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        final View view = findViewById(R.id.content);
    
        view.setFocusable(true);
        view.setFocusableInTouchMode(true);
    }
    

答案 10 :(得分:7)

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

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

android:focusable="true"
android:focusableInTouchMode="true"
android:clickable="true"

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

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

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

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中调用全新的自定义视图:

<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> 

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

答案 11 :(得分:7)

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

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

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是默认使用它的视图之一),如果它到达根视图,那是因为它没有被消耗,所以我关闭了软键盘。

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

答案 12 :(得分:6)

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

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

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

@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会使键盘隐藏和重新显示 - 在我的情况下,它需要这样,因为它显示您在两个输入组件之间切换。

答案 13 :(得分:5)

而不是遍历所有视图或覆盖dispatchTouchEvent。

为什么不仅要覆盖Activity的onUserInteraction(),还可以确保每当用户在EditText之外点击时,键盘都会关闭。

即使EditText位于scrollView内也可以使用。

@Override
public void onUserInteraction() {
    if (getCurrentFocus() != null) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    }
}

答案 14 :(得分:5)

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

问题:点击键盘或使用最少代码编辑文字时关闭软键盘。

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

单行解决方案:

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

更易读的解决方案:

@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绑定调用应该是这样的:

(@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设置为父布局,如上所述。

答案 15 :(得分:4)

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

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

答案 16 :(得分:4)

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

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

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

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

否则我们关闭它。

因此,总而言之,其工作原理如下:

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

    EditText

答案 17 :(得分:4)

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

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

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

中写这个
 yourLayout.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View view) {
                    hideKeyboard(view);
                }
            });
从listner调用的方法: -

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

答案 18 :(得分:3)

显示/隐藏软键盘的方法

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

    }

我希望它们有用

答案 19 :(得分:2)

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

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

答案 20 :(得分:2)

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

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

例如,您的活动:

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

答案 21 :(得分:2)

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

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

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

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

注意

  

findViewById(android.R.id.content)

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

干杯:)

答案 22 :(得分:1)

活动

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

答案 23 :(得分:1)

好吧,您可以使用此代码,使用您的主要布局ID代替&#34; mainRelativeLayout&#34;

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

    });

答案 24 :(得分:1)

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

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

答案 25 :(得分:1)

@Override
    public boolean onTouchEvent(MotionEvent event) {
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.
                INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        return true;
    }

答案 26 :(得分:1)

这可能已经过时但我通过实现自定义类

来实现这一点
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类,每个容器相对/线性布局都应该实现这一点。

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

并像这样实现:

Parent.setOnClickListener( new DismissKeyboardListener(this) ); 

关键字是针对Activity的。因此,如果您使用片段,则使用getActivity();

---如果对你有帮助,请竖起大拇指...... ---欢呼拉尔夫---

答案 27 :(得分:1)

在Kotlin中,我们可以执行以下操作。无需迭代所有视图。它也适用于片段。

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

答案 28 :(得分:1)

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

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,参见下面的代码

@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将被调用焦点已经改变现在你可以做任何你想做的事情希望它有效

答案 29 :(得分:1)

我这样做了:

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

隐藏键盘代码

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

完成

答案 30 :(得分:1)

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

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

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

答案 31 :(得分:1)

我稍微修改了@ navneeth-g答案,添加了空活动焦点处理,创建了多个实例OnTouchListener,在小键盘隐藏和滚动屏幕而不隐藏键盘时移除焦点,方便在小型设备上使用。

//In general, the view parameter is root layout
fun Activity.hideKeyboardOnClickOutsideEditText(view: View) {
    // Set up touch listener for non-text box views to hide keyboard.
    var previousAction = 0
    val onTouchListener = View.OnTouchListener { v, event ->
        if (currentFocus != null
            && event.action != MotionEvent.ACTION_DOWN
            && event.action != MotionEvent.ACTION_MOVE
            && previousAction != MotionEvent.ACTION_MOVE
        ) {
            currentFocus?.clearFocus()
            v?.hideKeyboard()
        }
        previousAction = event.action
        false
    }

    if (view !is EditText) {
        view.setOnTouchListener(onTouchListener)
    }

    //If a layout container, iterate over children and seed recursion.
    if (view is ViewGroup) {
        for (i in 0 until view.childCount) {
            val innerView = view.getChildAt(i)
            hideKeyboardOnClickOutsideEditText(innerView)
        }
    }
}

//in root layout.xml
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"

答案 32 :(得分:0)

这对我来说是最简单的解决方案(由我自己制定)。

这是隐藏键盘的方法。

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

现在可以从XML文件的“设计”视图或在XML文件的“文本”视图中的下面的代码中,将活动的父级布局的onclick属性设置为以上方法hideKeyboard

android:onClick="hideKeyboard"

答案 33 :(得分:0)

您可以实现View.onClickListener并重写onClick方法,并将此onclicklistener设置为Layout

int8

答案 34 :(得分:0)

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

首先添加到布局xml的根视图:     机器人:可点击=&#34;真&#34;     机器人:focusableInTouchMode =&#34;真&#34;

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

 @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(在任何扩展活动上)失去焦点时,键盘都将被隐藏。

P.S。 hideKeyboard方法:

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

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

答案 35 :(得分:0)

通过@sumit sonawane添加到先前的答案中,如果用户正在滚动,此解决方案将不会隐藏键盘。

public long pressTime = 0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        pressTime = System.currentTimeMillis();
    }
    else if (ev.getAction() == MotionEvent.ACTION_UP) {
        long releaseTime = System.currentTimeMillis();
        if (releaseTime-pressTime < 200) {
            if (getCurrentFocus() != null) {
                GhostTube.print("BottomNavActivity", "Touch event with keyboard detected...");
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent(ev);
}

将代码添加到您的活动中,还将处理片段。

答案 36 :(得分:0)

唯一有效的代码

private var viewHeight = 0

private fun setRootViewListener() {
    binding.root.apply {
        viewTreeObserver.addOnGlobalLayoutListener {
            viewHeight = height
        }
    }
}

override fun dispatchTouchEvent(event: MotionEvent): Boolean {
    currentFocus?.let {
        if (it is EditText && event.y < viewHeight - it.measuredHeight) {
            hideKeyboard(it)
        }
    }
    return super.dispatchTouchEvent(event)
}

答案 37 :(得分: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
}

答案 38 :(得分:0)

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

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

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

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

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

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受到影响:

parentLayout.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    hideSoftKeyboard(your_activity_name.this);
                }
            }
        });

答案 39 :(得分: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)上测试过。

如果您需要拖动检查,请长按,...,以上显示评论。

答案 40 :(得分: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;
            }
        });

答案 41 :(得分: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;
}

答案 42 :(得分:0)

我在费尔南多·卡马拉戈的解决方案上略有变化。在我的onCreate方法中,我将一个onTouchListener附加到根视图,但是发送视图而不是活动作为参数。

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

在另一个Utils类中是......

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

答案 43 :(得分:0)

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

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

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

答案 44 :(得分:-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(LOGSignUpActivity.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);
            }
        }
    }