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

hta*_*oya 340 android android-softkeyboard

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

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

Nav*_*h G 556

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

public static void hideSoftKeyboard(Activity activity) {
    InputMethodManager inputMethodManager = 
        (InputMethodManager) activity.getSystemService(
            Activity.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow(
        activity.getCurrentFocus().getWindowToken(), 0);
}
Run Code Online (Sandbox Code Playgroud)

您可以将其放在实用程序类中,或者如果要在活动中定义它,请避免使用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是全部,只需setContentView在您的活动中调用此方法即可.如果您想知道要传递什么参数,它是id父容器的参数.将id容器分配给您的父容器

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

并打电话setupUI(findViewById(R.id.parent)),就是这样.

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

希望能帮助到你.

如果您使用多个活动,则将父公布定义为公共ID <RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>

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

  • 不确定是否有其他人遇到此问题,但如果没有任何重点,这会导致应用程序在调用hideSoftKeyboard时崩溃.您可以通过使用`if(activity.getCurrentFocus()!= null){...}来包围方法的第二行来解决这个问题. (23认同)
  • 这种方法的问题在于它假定所有其他视图都不需要为它们设置`OnTouchListener`.您可以将`ViewGroup.onInterceptTouchEvent(MotionEvent)`中的逻辑设置为根视图. (13认同)
  • 应该不是很难?我现在没有Android编程了,所以如果我错了,请纠正我.您可以随时以某种方式跟踪焦点的EditText,并在OnTouchEvent期间请求它失去焦点? (4认同)
  • 当我单击其他控件并保持键盘打开时不起作用 (2认同)

vid*_*ida 268

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

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

        android:clickable="true" 
        android:focusableInTouchMode="true" 
    
    Run Code Online (Sandbox Code Playgroud)
  2. 实现hideKeyboard()方法

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

        edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus) {
                    hideKeyboard(v);
                }
            }
        });
    
    Run Code Online (Sandbox Code Playgroud)

正如下面的一条评论中所指出的,如果父视图是ScrollView,这可能不起作用.对于这种情况,可以在ScrollView正下方的视图上添加clickable和focusableInTouchMode.

  • 在我看来,这是正确的答案.更少的代码,没有不必要的迭代...... (66认同)
  • 我非常喜欢这个答案.有一点需要注意的是,在将`clickable`和`focusableInTouchMode`添加到我的根`ScrollView`元素时,这对我不起作用.我不得不添加到我的`EditText`的直接父级,它是一个`LinearLayout`. (13认同)
  • 为我工作完美.但是,如果你有两个edittext小部件,你需要确保正确处理它们两者的onfocus,否则你将不必要地切换键盘隐藏. (9认同)
  • @Shrikant-我也看到带有多个编辑文本的闪烁。我只是在父级而不是每个编辑文本上设置了onFocusChangeListener,然后将条件切换为if(hasFocus){hideKeyboard(v); }尚未注意到闪烁会切换btwn编辑文本。 (2认同)

roe*_*pit 56

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

这是我的解决方案.添加OnTouchListener到您的主要布局,即:

findViewById(R.id.mainLayout).setOnTouchListener(this)
Run Code Online (Sandbox Code Playgroud)

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

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
Run Code Online (Sandbox Code Playgroud)

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


Sau*_*eek 39

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

InputMethodManager imm = (InputMethodManager) getSystemService(
    Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
Run Code Online (Sandbox Code Playgroud)

在这里通过HIDE_IMPLICIT_ONLY位置showFlag0位置hiddenFlag.它将强制关闭软键盘.

  • 谢谢,它的工作.....最重要的是我尝试过,但是当我从对话框中获取价值时,editext text和closoing对话框... (2认同)
  • 抱歉,但是此方法为切换状态,因此如果键盘状态已关闭,它将显示键盘 (2认同)

小智 37

只需覆盖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);
}
Run Code Online (Sandbox Code Playgroud)

  • 不错,但它好得令人难以置信:简单,非常短,而且它有效......唉,有一个问题:当显示键盘时,每次我们触摸询问键盘的 EditText 时,它都会下降并自动起来。 (11认同)
  • 简单的解决方案,添加活动,它将同时处理片段 (4认同)
  • 绝妙的解决方案 (3认同)

hta*_*oya 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);
}
Run Code Online (Sandbox Code Playgroud)

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

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


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

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

  • 为了将来帮助其他人,你会考虑编写你的答案中的代码来包含你的`getFields()`方法吗?它不一定非常精确,只是一个例子,可能只是一些注释表明它返回一个`EditText`对象的数组. (7认同)

Ser*_*tov 14

使用OnFocusChangeListener.

例如:

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

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

  • 问题是当我单击Label或其他不可聚焦的视图时,edittext不会失去焦点. (9认同)
  • onTouchEvent多次调用,所以这也不是一个好习惯 (2认同)

Jis*_*hen 13

我在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);
}
Run Code Online (Sandbox Code Playgroud)

我测试了它,效果很好!


Hoa*_*inh 11

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

@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;
}
Run Code Online (Sandbox Code Playgroud)

这就是你需要做的一切


Phi*_*hil 11

使用TextInputEditText的更多KotlinMaterial Design方法(这种方法也与EditTextView兼容)......

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

android:focusable="true"
android:focusableInTouchMode="true"
android:clickable="true"
Run Code Online (Sandbox Code Playgroud)

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

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

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

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> 
Run Code Online (Sandbox Code Playgroud)

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


SKG*_*SKG 9

而不是遍历所有视图或覆盖 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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Fer*_*rgo 8

我修改了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);
}
Run Code Online (Sandbox Code Playgroud)

但是,不是为每个视图注册一个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;
    }
});
Run Code Online (Sandbox Code Playgroud)


fje*_*fje 8

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

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

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

这是我的结果:

@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);
}
Run Code Online (Sandbox Code Playgroud)

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

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

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

    view.setFocusable(true);
    view.setFocusableInTouchMode(true);
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是复杂布局的最佳解决方案.但到目前为止我发现了两个缺点:1.EditText上下文菜单无法点击 - 任何点击它都会导致EditText 2失去焦点.当我们的EditText位于视图底部并且我们长按它(选择单词),之后键盘显示我们的"点击点"是在键盘上,而不是在EditText上 - 所以我们再次失去焦点:/ (2认同)

Sai*_*Sai 7

在 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)
}
Run Code Online (Sandbox Code Playgroud)

  • 这可行,但有一个错误。例如,如果我想在文本视图中粘贴文本,键盘会隐藏然后显示。这有点烦人。 (2认同)

Chr*_* R. 6

我喜欢dispatchTouchEventhtafoya 的调用方法,但是:

  • 我不明白计时器部分(不知道为什么要测量停机时间?)
  • 我不喜欢在每次视图更改时注册/取消注册所有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());
}
Run Code Online (Sandbox Code Playgroud)

有一个缺点:

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


Cha*_*son 6

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

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

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

单线解决方案:

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

更易读的解决方案:

@OnClick(R.id.activity_signup_layout) 
public void closeKeyboard() {
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
Run Code Online (Sandbox Code Playgroud)

说明:将 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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


小智 5

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

android:id="@+id/loginParentLayout"
android:clickable="true"
android:focusableInTouchMode="true"
Run Code Online (Sandbox Code Playgroud)

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

 yourLayout.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View view) {
                    hideKeyboard(view);
                }
            });
Run Code Online (Sandbox Code Playgroud)

从侦听器调用的方法:-

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


归档时间:

查看次数:

330779 次

最近记录:

6 年,2 月 前