EditView外部点击隐藏软键盘需求

业务场景

在工作过程中,遇到一个需求。某个页面,需要在EditView输入数值,在软键盘下滑和点击EditView外部区域后,EditView失去焦点,并且开始计算最终金额。因为该页面没有其他控件可以抢占EditView焦点,所以需要做一些额外处理来完成这个需求。下面是步骤

第一步,重写EditView父控件的事件分发方法,判断是否有外部点击

使用下面这个类,判断是否是EditView的外部点击。还可以调用addList(View)方法,把该父布局下的子控件同时加入判断,判断这些子控件和EditView的区域外点击。
调用步骤,

  1. 在xml中,把这个DispatchTouchFrameLayout当作EditView的父控件,这里也可以修改成RelativeLayout或者LinearLayout都可以。
  2. setEditView(EditView) 加入判断的editView
  3. addList(View) 加入需要判断的其他View,可选
  4. setRunnable(Runnable),添加触发后的响应事件

/**
 * created time: 2019/6/18
 * 可判断是否在EditView以外区域发生了点击
 */
public class DispatchTouchFrameLayout extends FrameLayout {

    public DispatchTouchFrameLayout(@NonNull Context context) {
        super(context);
    }

    public DispatchTouchFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public DispatchTouchFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    EditText editText;
    //其他不响应区域view
    ArrayList<View> notCheckViewList = new ArrayList<>();

    public void addList(View view) {
        notCheckViewList.add(view);
    }

    private EditText getEditText() {
        return editText;
    }

    public void setEditText(EditText editText) {
        this.editText = editText;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        this.editText = null;
        notCheckViewList.clear();
        notCheckViewList = null;
    }

    //点击以外区域后的响应事件
    Runnable runnable;

    public void setRunnable(Runnable runnable) {
        this.runnable = runnable;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            EditText v = getEditText();
            if (isShouldHideInput(v, ev)) {
                if (runnable != null)
                    runnable.run();
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 是否应该触发eidtView区域外的点击事件
     *
     * @param v
     * @param event
     * @return
     */
    private boolean isShouldHideInput(EditText v, MotionEvent event) {
        if (v != null && v.isFocused()) {
            boolean isOnEditView = isOnViewArea(v, event);
            if (isOnEditView) return false;
            //点击其他list内view区域,也不响应
            for (View view : notCheckViewList) {
                boolean onViewArea = isOnViewArea(view, event);
                isOnEditView = isOnEditView || onViewArea;
            }
            return !isOnEditView;
        }
        return false;
    }

    /**
     * 判断某个点击时间是否在这个view区域内
     *
     * @param view
     * @param event
     * @return true表示在范围内
     */
    private boolean isOnViewArea(View view, MotionEvent event) {
        if (view == null) return false;
        int[] leftTop = {0, 0};
        //获取输入框当前的location位置
        view.getLocationInWindow(leftTop);
        //取window坐标
        int[] containerTop = {0, 0};
        getLocationInWindow(containerTop);
        int left = leftTop[0];
        int top = leftTop[1];
        int bottom = top + view.getHeight();
        int right = left + view.getWidth();
        float x = containerTop[0] + event.getX();
        float y = containerTop[1] + event.getY();
        return x > left && x < right
                && y > top && y < bottom;
    }

}

第二步,监听软键盘下滑事件

监听软件盘下滑事件,setOnSoftKeyBoardChangeListener(), keyBoardHide()触发时响应runnable

/**
 * description: 软键盘弹起和下滑监听类
 */
public class KeyBoardChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
    View rootView;
    int rootViewVisibleHeight; //纪录根视图的显示高度,每次改变重新赋值
    final int HEIGHT_BOUND = 200;       //200px为判断界限值

    public KeyBoardChangeListener(Activity activity) {
        if (activity == null)
            return;
        rootView = findContentView(activity);
        addContentTreeObserver();
    }

    private View findContentView(Activity activity) {
        return activity.getWindow().getDecorView();
    }

    private void addContentTreeObserver() {
        if (rootView != null)
            rootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        Rect r = new Rect();
        rootView.getWindowVisibleDisplayFrame(r);
        int visibleHeight = r.height();
        if (rootViewVisibleHeight == 0) {   //初始化高度
            rootViewVisibleHeight = visibleHeight;
            return;
        }
        //可见高度不变,未发生软键盘变化
        if (rootViewVisibleHeight == visibleHeight)
            return;
        int diffHeight = Math.abs(rootViewVisibleHeight - visibleHeight);
        if (diffHeight > HEIGHT_BOUND) {                         //如果变化高度大于界限
            if (rootViewVisibleHeight > visibleHeight) {        //可见高度变小,表示软键盘弹出
                if (onSoftKeyBoardChangeListener != null)
                    onSoftKeyBoardChangeListener.keyBoardShow(diffHeight);
            } else {
                if (onSoftKeyBoardChangeListener != null)
                    onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight);
            }
            rootViewVisibleHeight = visibleHeight;
        }
    }

    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;

    public void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;
    }

    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);

        void keyBoardHide(int height);
    }

    public void release() {
        if (rootView != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
                rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
        rootView = null;
    }
}

第三步,隐藏软键盘和取消EditView焦点

运行的runnable事件中,加上隐藏软键盘,取消EditView焦点,开始计算等逻辑即可

//隐藏软键盘
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(((Activity) context).getWindow().getDecorView().getWindowToken(), 0);

//EditView取消焦点和光标
editView.clearFocus();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值