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

时间:2013-12-20 22:59:34

标签: android android-layout

我有EditText名为myTextview。我希望当我点击EditText时显示软键盘,但如果我点击EditText之外,我就会关闭。所以我使用下面的方法。但是当我在视图外单击时,键盘不会被忽略(我单击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);
            }

        }
    });

9 个答案:

答案 0 :(得分:47)

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

覆盖您的活动中的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);
    }
}

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

答案 1 :(得分:15)

也许有点容易:

在编辑文本上设置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);
}

答案 2 :(得分:3)

这样,只有触摸可以获得焦点的视图时,键盘才会消失。我建议你做以下事情:

像这样创建一个自定义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);
    }
}

然后将自定义视图添加为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" />

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

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

答案 3 :(得分:3)

使用以下代码。

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

它对我有用。

答案 4 :(得分:2)

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

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

解决方案:外部库称为 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开发。考虑一下。

答案 5 :(得分:0)

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

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
    }

}

在此布局下包裹您的EditText和其他亲戚View,并设置preDispatchTouchEvent以在事件不高于此时解除EditText

检查this OS questionofficial doc,以便更深入地了解触摸事件传递。

答案 6 :(得分:0)

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

答案 7 :(得分:0)

我在下面的过程中使用。完美地为我工作。在活动类中添加以下函数。

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

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

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

我被检入片段。我需要任务状态为“焦点”状态。集中精力我需要完成一些任务。

答案 8 :(得分:0)

在科特林,我使用了波纹管代码,效果很好

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

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