在android中单击EditText之外时关闭键盘

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20713273/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:20:13  来源:igfitidea点击:

Dismiss keyboard when click outside of EditText in android

androidandroid-layout

提问by user3093402

I have an EditTextcalled myTextview. I want the soft keyboard to show when I click on the EditTextbut then dismiss if I click outside of the EditText. So I use the method below. But the keyboard does not dismiss when I click outside the view (I click a TextView). How do I fix this code?

我有一个EditTextmyTextview. 我希望软键盘在我点击时显示,EditText但如果我在EditText. 所以我使用下面的方法。但是当我在视图外单击时键盘不会关闭(我单击 a TextView)。如何修复此代码?

myTextview.setOnFocusChangeListener(new OnFocusChangeListener() {

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {
                getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
            } else {
                InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(myTextview.getWindowToken(), 0);
            }

        }
    });

回答by Felipe R. Saruhashi

I found a better solution:

我找到了一个更好的解决方案:

Override the dispatchTouchEventmethod in your Activity.

覆盖dispatchTouchEvent您的活动中的方法。

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    View v = getCurrentFocus();

    if (v != null && 
            (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && 
            v instanceof EditText && 
            !v.getClass().getName().startsWith("android.webkit.")) {
        int scrcoords[] = new int[2];
        v.getLocationOnScreen(scrcoords);
        float x = ev.getRawX() + v.getLeft() - scrcoords[0];
        float y = ev.getRawY() + v.getTop() - scrcoords[1];

        if (x < v.getLeft() || x > v.getRight() || y < v.getTop() || y > v.getBottom())
            hideKeyboard(this);
    }
    return super.dispatchTouchEvent(ev);
}

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

This is applicable even if you are working with webview.

即使您正在使用 webview,这也适用。

回答by pat

Maybe a little bit easier:

也许更容易一点:

Set a focusChangedListener on your edit text and then just hide the keyboard if you don't have focus.

在您的编辑文本上设置一个 focusChangedListener ,然后如果您没有焦点就隐藏键盘。

yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(!hasFocus){
            hideKeyboard();
        }               
    }
});

private void hideKeyboard() {
    InputMethodManager imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(yourEditText.getWindowToken(), 0);
}

回答by diegocarloslima

This way, the keyboard will only disappear when you touch a view that can gain focus. I suggest you to do the following:

这样,只有当您触摸可以获得焦点的视图时,键盘才会消失。我建议您执行以下操作:

Create a custom ViewGroup like this:

像这样创建一个自定义的 ViewGroup:

public class TouchLayout extends LinearLayout {

    private OnInterceptTouchEventListener mListener;

    public TouchLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if(mListener != null) {
            return mListener.onInterceptTouchEvent(event);
        }
        return super.onInterceptTouchEvent(event);
    }

    public void setOnInterceptTouchEventListener(OnInterceptTouchEventListener listener) {
        mListener = listener;
    }

    public interface OnInterceptTouchEventListener {
        public boolean onInterceptTouchEvent(MotionEvent event);
    }
}

Then add the custom View as a root of your xml layout:

然后将自定义视图添加为 xml 布局的根:

<com.example.TouchLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

        <EditText
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

And in your Activity you should do the following:

在您的活动中,您应该执行以下操作:

final TouchLayout root = (TouchLayout) findViewById(R.id.root);
final EditText text = (EditText) findViewById(R.id.text);
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

root.setOnInterceptTouchEventListener(new OnInterceptTouchEventListener() {

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        final View v = getCurrentFocus();
        if(v != null && v.equals(text)) {
            final int screenCords[] = new int[2];
            text.getLocationOnScreen(screenCords);
            final Rect textRect = new Rect(screenCords[0], screenCords[1], screenCords[0] + text.getWidth(), screenCords[1] + text.getHeight());
            if(!textRect.contains(event.getRawX(), event.getRawY() {
                imm.hideSoftInputFromWindow(myTextview.getWindowToken(), 0);
                // Optionally you can also do the following:
                text.setCursorVisible(false);
                text.clearFocus(); 
            }
        }
        return false;
    }
};

回答by Ganpat Kaliya

use following code.

使用以下代码。

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

it's working for me.

它对我有用。

回答by Charles Woodson

Plea:I recognize I have no clout, but please take my answer seriously.

Plea:我承认我没有影响力,但请认真对待我的回答。

Problem:Dismiss soft keyboard when clicking away from keyboard or edit text with minimal code.

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

Solution:External library known as Butterknife.

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

One Line Solution:

单线解决方案:

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

More Readable Solution:

更具可读性的解决方案:

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

Explanation:Bind OnClick Listener to the activity's XML Layout parent ID, so that any click on the layout (not on the edit text or keyboard) will run that snippet of code which will hide the keyboard.

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

Example:If your layout file is R.layout.my_layout and your layout id is R.id.my_layout_id, then your Butterknife bind call should look like:

示例:如果您的布局文件是 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 Documentation Link:http://jakewharton.github.io/butterknife/

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

Plug:Butterknife will revolutionize your android development. Consider it.

Plug:Butterknife 将彻底改变您的 android 开发。考虑一下。

回答by FreakyAli

For all those who are looking for a Xamarin Android code for this :

对于所有正在为此寻找 Xamarin Android 代码的人:

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

回答by Shohel Rana

I use below Process. It's Working For Me Perfectly. Add below function in your activity Class.

我使用以下流程。它非常适合我。在您的活动类中添加以下功能。

  override fun dispatchTouchEvent(event: MotionEvent): Boolean {
    if (event.action == MotionEvent.ACTION_DOWN) {
        val v = currentFocus
        if (v is EditText) {
            val outRect = Rect()
            v.getGlobalVisibleRect(outRect)
            if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) {
                Log.d("focus", "touchevent")
                v.clearFocus()
                val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.hideSoftInputFromWindow(v.windowToken, 0)
            }
        }
    }
    return super.dispatchTouchEvent(event)
}

Then I will Check Focus status in my fragment.

然后我将在我的片段中检查焦点状态。

appCompatEditText.onFocusChangeListener = View.OnFocusChangeListener { view, hasFocus ->
                if (!hasFocus) {
                    toast("Focus Off")
                }else {
                    toast("Focus On")
                }
            }

I was Checked in Fragment. I needed Focus status for my task Requirement. Focus Out I needed some task.

我在 Fragment 中被检查。我的任务要求需要焦点状态。集中注意力我需要一些任务。

回答by Enamul Haque

In Kotlin, I have used bellow code which is working fine

在 Kotlin 中,我使用了运行良好的波纹管代码

override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
    val v = currentFocus
    if (v != null && (ev.action == MotionEvent.ACTION_UP || ev.action == MotionEvent.ACTION_MOVE)
        && v is EditText
        && !v.javaClass.name.startsWith("android.webkit.")
    ) {
        val scrcoords = IntArray(2)
        v.getLocationOnScreen(scrcoords)
        val x = ev.rawX + v.getLeft() - scrcoords[0]
        val y = ev.rawY + v.getTop() - scrcoords[1]
        if (x < v.getLeft() || x > v.getRight() || y < v.getTop() || y > v.getBottom()
        ) hideKeyboard(this)
    }
    return super.dispatchTouchEvent(ev)
}

fun hideKeyboard(activity: Activity?) {
    if (activity != null && activity.window != null && activity.window.decorView != null
    ) {
        val imm = activity
            .getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(
            activity.window.decorView
                .windowToken, 0
        )
    }
}

In Java, I have used bellow code which is working fine

在 Java 中,我使用了运行良好的波纹管代码

  @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    View v = getCurrentFocus();

    if (v != null
            && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE)
            && v instanceof EditText
            && !v.getClass().getName().startsWith("android.webkit.")) {
        int scrcoords[] = new int[2];
        v.getLocationOnScreen(scrcoords);
        float x = ev.getRawX() + v.getLeft() - scrcoords[0];
        float y = ev.getRawY() + v.getTop() - scrcoords[1];

        if (x < v.getLeft() || x > v.getRight() || y < v.getTop()
                || y > v.getBottom())
            hideKeyboard(this);
    }
    return super.dispatchTouchEvent(ev);
}

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

回答by Lym Zoy

Touch event on a View will start with ACTION_DOWNfrom being passed from top to this View in view hierachy. Override dispatchTouchEventto do additional things. Here's an example to extend from FrameLayoutin kotlin:

视图上的触摸事件ACTION_DOWN将从在视图层次结构中从顶部传递到此视图开始。覆盖dispatchTouchEvent以执行其他操作。这是FrameLayout在 kotlin 中扩展的示例:

class TLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet?=null):
        FrameLayout(context, attrs){

    var preDispatchTouchEvent: ((ev: MotionEvent?)->Boolean)? = null

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        if (preDispatchTouchEvent==null || !preDispatchTouchEvent!!.invoke(ev)) {
            super.dispatchTouchEvent(ev)
        }
        return true
    }

}

Wrap your EditTextand other relative Views under this layout, and set preDispatchTouchEventto dismiss EditTextwhen event is not above it.

将您EditText和其他亲属包裹View在此布局下,并在事件不在其上方时设置preDispatchTouchEvent为关闭EditText

Check this OS questionand official docto have deeper understanding of touch event delivering.

检查此操作系统问题官方文档,以更深入地了解触摸事件传递。