android点击EditText外区域收起键盘

在日常开发中,Activity中可能有比较复杂的布局,比如嵌套很多Fragment,所以针对该需求,通常的做法为放到Activity中统一处理。

常规思路为在dispatchTouchEvent中不拦截MotionEvent,但是会根据event是否落在EditText中做相应的处理,具体做法为

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideInput(v, ev)) {
                hideInputMethod(this, v);
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    private boolean isShouldHideInput(View v, MotionEvent event) {

        if (v != null && (v instanceof EditText)) {
            int[] leftTop = {0, 0};
            v.getLocationInWindow(leftTop);
            int left = leftTop[0], top = leftTop[1], bottom = top + v.getHeight(), right = left
                    +
                    v.getWidth();
            if (event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom) {
                return false;
            } else {
                return true;
            }
        }
        return false;
    }

    private Boolean hideInputMethod(Context context, View v) {

        v.clearFocus();
        InputMethodManager imm = (InputMethodManager)context
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
        }
        return false;
    }

在Down事件时如果event不在当前获取焦点的EditText中,则收起键盘,另外清除焦点,注意EditText的parent需要设置如下属性保证可以获取焦点,一般直接设置在activity的顶层布局中

android:focusable="trur"
android:focusableInTouchMode="trur"

如上处理后会发现用户在EditText间切换焦点时不正常,键盘会出现先收起再弹出,我们要做的是能判断MotionEvent消费后是否由其它EditText获取到了焦点,如果是的话则不收起键盘。

当用户点击其它EditText时,只有Up事件发生时才会完成focus切换,所以做法有两种,第一种比较简单,延时200ms再判断就可以覆盖绝大部分场景,不过会出现用户按住其它EditText时键盘收起等情况。

    private boolean hideInputMethod(Context context, View v) {

        // 延时100ms判断焦点是否还在edittext,不在的话则隐藏键盘
        mHandler.postDelayed(() -> {
            View current = getCurrentFocus();
            if (current == v) {
                v.clearFocus();
                InputMethodManager imm = (InputMethodManager)context
                        .getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm != null) {
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
        }, 200);
        return false;
    }

另外一个更好的方法是在dispatchTouchEvent中监听焦点的变化,如果down和up时焦点无变化,则认为需要收起键盘,与上面类似。具体代码如下

    boolean pendingCollapseKeyword = false;
    View focusedView;

    // 点击非输入框位置优先隐藏软键盘
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            pendingCollapseKeyword = isShouldHideInput(ev);
            if (pendingCollapseKeyword) focusedView = getCurrentFocus();
        } else if (ev.getAction() == MotionEvent.ACTION_UP) {
            if (pendingCollapseKeyword) {
                hideInputMethod(this);
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    private boolean isShouldHideInput(MotionEvent event) {

        View v = getCurrentFocus();
        if (v instanceof EditText) {
            int[] location = {0, 0};
            v.getLocationInWindow(location);
            return event.getX() < location[0]
                   || event.getX() > location[0] + v.getWidth()
                   || event.getY() < location[1]
                   || event.getY() > location[1] + v.getHeight();
        }
        return false;
    }

    // 抬起手指时如果焦点还在原来的EditText则收起键盘
    private void hideInputMethod(Context context) {

        View v = getCurrentFocus();
        if (v == focusedView) {
            focusedView.clearFocus();
            InputMethodManager imm = (InputMethodManager)context
                    .getSystemService(Context.INPUT_METHOD_SERVICE);
            if (imm != null) {
                imm.hideSoftInputFromWindow(focusedView.getWindowToken(), 0);
            }
        }
    }

如上同时兼顾了两个需求

  1. 点击EditText外收起键盘
  2. 点击其它EditText保持键盘状态不变
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值