zoukankan      html  css  js  c++  java
  • Android:Dialog中隐藏键盘的注意事项

    场景:弹出一个Dialog。里面有一个EditText。用来输入内容。由于输入时。须要弹出键盘。所以当Dialog消失时。键盘要一起隐藏。

    如今我们做一个自己定义的Dialog

    MyDialog extends Dialog
    一開始觉得这个功能非常easy实现,于是写了以下的代码

    //Dialog的构造函数中写
        this.setOnDismissListener(new OnDismissListener() {
          @Override
          public void onDismiss(DialogInterface dialog) {
            hideKeyBoard();
          }
        });
    //edContent是输入框
      public void hideKeyBoard(){
        InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(edContent.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
      }

    执行之后,发现根本无法隐藏。看看hideSoftInputFromWindow中干了啥

        public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
                ResultReceiver resultReceiver) {
            checkFocus();
            synchronized (mH) {
                if (mServedView == null || mServedView.getWindowToken() != windowToken) {
                    return false;
                }
    
                try {
                    return mService.hideSoftInput(mClient, flags, resultReceiver);
                } catch (RemoteException e) {
                }
                return false;
            }
        }
    跟踪进去发现參数 windowToken 是 null,并且 mServedView 也是null,所以直接返回false,无法隐藏。

    也就是说,你监听Cancel或者Dismiss都是不行的。由于此时Dialog已经消失。用于输入的服务窗口已经是null了,所以你要想 隐藏键盘,就须要在Dismiss之前处理,那这个入口在哪呢?

    为了当点击空白处时,能够隐藏Dialog,所以我们在构造函数中加了一句话

    this.setCanceledOnTouchOutside(true);
    所以当我们点击空白区域时。会触发Dialog的onTouchEvent

        public boolean onTouchEvent(MotionEvent event) {
            if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {
                cancel();
                return true;
            }
            
            return false;
        }

    这里会调用基类Window的shouldCloseOnTouch方法,来推断能否够关闭,这里我们看到假设满足,就直接cancel()了,

        public void cancel() {
            if (!mCanceled && mCancelMessage != null) {
                mCanceled = true;
                // Obtain a new message so this dialog can be re-used
                Message.obtain(mCancelMessage).sendToTarget();
            }
            dismiss();
        }
    这里面就会dismiss掉Dialog,所以我们发现,在dismiss前。我们根本无法干预,真是个悲剧。

    所以我们仅仅能重载onTouchEvent方法。并且自己推断能否够关闭(也就是把以下代码迁移到你的代码中!

        public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
            if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
                    && isOutOfBounds(context, event) && peekDecorView() != null) {
                return true;
            }
            return false;
        }
    
        private boolean isOutOfBounds(Context context, MotionEvent event) {
            final int x = (int) event.getX();
            final int y = (int) event.getY();
            final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
            final View decorView = getDecorView();
            return (x < -slop) || (y < -slop)
                    || (x > (decorView.getWidth()+slop))
                    || (y > (decorView.getHeight()+slop));
        }

    自己代码中这样

      @Override
      public boolean onTouchEvent(MotionEvent event) {
        if (isShowing() && shouldCloseOnTouch(getContext(),event)){
          hideKeyBoard();
        }
        return super.onTouchEvent(event);
      }
      public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN
                && isOutOfBounds(context, event) && getWindow().peekDecorView() != null) {
          return true;
        }
        return false;
      }
      private boolean isOutOfBounds(Context context, MotionEvent event) {
        final int x = (int) event.getX();
        final int y = (int) event.getY();
        final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
        final View decorView = getWindow().getDecorView();
        return (x < -slop) || (y < -slop)
                || (x > (decorView.getWidth()+slop))
                || (y > (decorView.getHeight()+slop));
      }

    真是有点无奈。眼下想到的方法就是这样。哪位有更好的方法,欢迎提供!



  • 相关阅读:
    小程序---云开发----云函数
    小程序的基本概念-生命周期(组件 wxml)
    小程序的基本概念
    vue登录功能和将商品添加至购物车实现
    vue脚手架创建项目
    node.js评论列表和添加购物车数据库表创建
    学习脚手架--组件之间跳转与参数(组件之间参数)
    node.js 需要注意知识点
    如何查询小程序官方手册
    vue ui九宫格、底部导航、新闻列表、跨域访问
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/8398882.html
Copyright © 2011-2022 走看看