qq_20258523 2018-06-27 03:39 采纳率: 0%
浏览 3615
已结题

关于 dialog中弹出软键盘 dialog位移到顶部 被切掉的问题及软键盘监听

dialog的高度和软键盘的高度加起来超过了屏幕的高度,这样dialog的顶部被切掉了,模仿平板系统设置中的方法,dialog中布局外面加一个ScrollView,在软键盘弹出收起的时候动态改变dialog的高度,但是网上找到的方法都无法监听到软键盘的弹出和收起,请问有什么有效的方法能解决这个问题吗?

  • 写回答

1条回答 默认 最新

  • sinat_34530417 2018-06-27 04:00
    关注

    一:适应键盘的弹起。
    我们知道,在Activity中如果要让布局不被软键盘遮挡,方法一般是在清单文件中配置windowSoftInputMode属性, windowSoftInputMode是Android1.5以后的一个新特性,主要是对软键盘操作的,主要有以下属性:

    stateUnspecified:软键盘的状态并没有指定,系统将选择一个合适的状态或依赖于主题的设置
    stateUnchanged:当这个activity出现时,软键盘将一直保持在上一个activity里的状态,无论是隐藏还是显示
    stateHidden:用户选择activity时,软键盘总是被隐藏
    stateAlwaysHidden:当该Activity主窗口获取焦点时,软键盘也总是被隐藏的
    stateVisible:软键盘通常是可见的
    stateAlwaysVisible:用户选择activity时,软键盘总是显示的状态
    adjustUnspecified:默认设置,通常由系统自行决定是隐藏还是显示
    adjustResize:该Activity总是调整屏幕的大小以便留出软键盘的空间
    adjustPan:当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分
    我们可以根据需求在清单文件中配置具体的属性,那么如果软键盘是基于Dialog弹出来的话该怎么办呢?毕竟我们没有清单文件来配置Dialog的属性。其实,在清单中配置的属性本质也是告诉当前界面对软键盘这种情况的处理。windowSoftInputMode的属性如果在清单文件中配置的话是这样写的:
    android:windowSoftInputMode="stateHidden|adjustPan"

    其实在清单文件中的某些配置,我们在Activity也能配置,在Activity中用代码设置话是这样写的:
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

    聪明的你看到这里可能已经看出来什么了,没错,两种方式的实质就是得到当前的窗口实例,来基于当前窗口设置的。我们来进入源码看一下,首先看getWindow()方法:
    public Window getWindow() { return mWindow; }

    很简单,得到当前的Window实例,再进入setSoftInputMode这个方法:

    public void setSoftInputMode(int mode) {
    final WindowManager.LayoutParams attrs = getAttributes();
    if (mode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED)
    {

    attrs.softInputMode = mode; mHasSoftInputMode = true;
    } else {
    mHasSoftInputMode = false;
    }
    if (mCallback != null) {
    mCallback.onWindowAttributesChanged(attrs);
    }
    }```
    这个方法很短逻辑也很清晰,我们可以看到,倒数第三行代码,当窗口属性发生变化的时候,mCallback会回调一个方法执行某些操作,那么这个,mCallback是什么呢?在源码中搜索一下你会找到以下代码和注释:
    /** * Set the Callback interface for this window, used to intercept key

    events and other dynamic operations in the window.
    @param callback The desired Callback interface.
    */
    public void setCallback(Callback callback) {
    mCallback = callback;
    }```
    由注释我们可以看到mCallback是给当前窗口设置的一个回调接口,当窗口发生某些变化的时候可以通过这个回调接口执行某些操作。回到mCallback.onWindowAttributesChanged(attrs)这句代码,首先我们肯定知道,Activity肯定实现了这个接口,那么,还有其他的实现了这个接口吗?找到定义这个接口的地方:
    This is called whenever the current window attributes change. public void onWindowAttributesChanged(WindowManager.LayoutParams attrs);

    由注释我们也可以清楚的明白这个接口的用途:无论在什么时候都会被调用当窗口属性发生变化。在Android Studio中我们可以点击这个接口定义左边的向上箭头查看接口的实现类,我们发现,dialog也实现了这个接口,那么回到第一个需求,解决方法就简单多了,只需要自定义一个Dialog,然后重写onCreate方法,如下:

    super.onCreate(savedInstanceState); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
    }```
    其实跟在Activity中设置是一样的。

    二,基于Dialog监听软键盘的弹起和收下:
    其实看完第一个需求,我们可能已经猜想到,软键盘也是基于当前窗口的,它的弹起和收下肯定会引起当前窗口布局的属性发生变化,所以解决思路就有了:监听当前布局的变化。我这里是比较布局坐标中的下坐标的,因为如果键盘弹起的话,布局的下坐标肯定会变小。具体代码如下:
    @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
    if (oldBottom != 0 && bottom != 0 && (oldBottom - bottom > 0))
    {//软键盘弹起 doSomethinh..
    } else if (oldBottom != 0 && bottom != 0 && (bottom - oldBottom > 0))
    {//软件盘关闭 doSomethinh.. } }

    评论

报告相同问题?

悬赏问题

  • ¥20 matlab yalmip kkt 双层优化问题
  • ¥15 如何在3D高斯飞溅的渲染的场景中获得一个可控的旋转物体
  • ¥88 实在没有想法,需要个思路
  • ¥15 MATLAB报错输入参数太多
  • ¥15 python中合并修改日期相同的CSV文件并按照修改日期的名字命名文件
  • ¥15 有赏,i卡绘世画不出
  • ¥15 如何用stata画出文献中常见的安慰剂检验图
  • ¥15 c语言链表结构体数据插入
  • ¥40 使用MATLAB解答线性代数问题
  • ¥15 COCOS的问题COCOS的问题