10赞
330
当前位置:  开发笔记 > Android > 正文

详解Android中获取软键盘状态和软键盘高度

这篇文章主要介绍了详解Android中获取软键盘状态和软键盘高度的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下

详解Android中获取软键盘状态和软键盘高度

应用场景

在Android应用中有时会需要获取软键盘的状态(即软键盘是显示还是隐藏)和软键盘的高度。这里列举了一些可能的应用场景。

场景一

当软键盘显示时,按下返回键应当是收起软键盘,而不是回退到上一个界面,但部分机型在返回键处理上有bug,按下返回键后,虽然软键盘会自动收起,但不会消费返回事件,导致Activity还会收到这次返回事件,执行回退操作,这时就需要判断,如果软键盘刚刚由显示变为隐藏状态,就不执行回退操作。

场景二

当软键盘弹出后,会将界面底部到中间的一大部分全部挡住,如果用户要查看、操作被覆盖的区域,必须先收起软键盘,这会影响用户交互。所以通常需要在软键盘弹出后,将底部的一些View,例如Button,移到软键盘的上方,方便用户操作。

API的困境

Android SDK中没有提供任何API来直接获取软键盘的状态和软键盘的高度,网上很多资料说InputMethodManager的isActive()方法可以获取软键盘状态,不过实际测试发现,这个方法并没有什么用,如果它返回false,可以判断软键盘一定是隐藏的,但如果它返回true,软键盘既可能是显示的,也可能是隐藏的。所以并不能通过isActive()方法来判断软键盘究竟是显示还是隐藏的。要想获取软键盘的状态和软键盘的高度,只能通过间接方法实现。

注册布局变化监听

在Android中当软键盘由隐藏变为显示,或由显示变为隐藏时,会触发当前布局中View的全局布局变化。通过监听全局布局的变化就可以得知软键盘的状态。

Android框架提供了一个ViewTreeObserver类,它是一个View视图树的观察者类。ViewTreeObserver类中定义了一系列的公共接口(public interface)。当一个View attach到一个窗口上时就会创建一个ViewTreeObserver对象,这样当一个View的视图树发生改变时,就会调用该对象的某个方法,将事件通知给每个注册的监听者。

OnGlobalLayoutListener是ViewTreeObserver中定义的众多接口中的一个,它用来监听一个视图树中全局布局的改变或者视图树中的某个视图的可视状态的改变。当软键盘由隐藏变为显示,或由显示变为隐藏时,都会调用当前布局中所有存在的View中的ViewTreeObserver对象的dispatchOnGlobalLayout()方法,此方法中会遍历所有已注册的OnGlobalLayoutListener,执行相应的回调方法,将全局布局改变的消息通知给每个注册的监听者。

向一个View中的ViewTreeObserver注册OnGlobalLayoutListener的方法如下。

view.getViewTreeObserver().addOnGlobalLayoutListener(listener);

注册OnGlobalLayoutListener时有一些需要注意的地方。

  • 注册的监听在不使用时需要调用removeOnGlobalLayoutListener或removeGlobalOnLayoutListener来移除监听,不然可能会导致内存泄露。通常可以在Activity的onCreate()方法中注册监听,在onDestory()方法中移除监听。
  • 并不是只有显示和隐藏软键盘会触发OnGlobalLayoutListener中的回调,一个View在绘制完成,或者消失时都会触发OnGlobalLayoutListener中的回调(由于在onCreate中无法获取一个View的宽度和高度,很多时候就是通过注册OnGlobalLayoutListener,在OnGlobalLayoutListener的回调中来获取一个View的宽度和高度)。

为了在OnGlobalLayoutListener的回调中准确的判断是否是由于软键盘状态改变引起的,以及获取软键盘的高度,还需要另外一个接口。

获取当前窗口可见的显示区域大小

在View中提供了一个方法getWindowVisibleDisplayFrame(),此方法会返回该view所附着的窗口的可见区域大小。当软键盘显示时,窗口的可见区域大小会被压缩,当软键盘隐藏时,窗口的可见区域大小会还原。不过并不是只有软键盘的显示和隐藏会影响窗口的可见区域大小,像大多数的平板和部分手机上有一排虚拟按键(虚拟的返回键,Home键等),虚拟按键的显示和隐藏也会引起窗口可见区域的变化。不过好在除了软键盘外,其他操作对窗口可见区域的影响占整个屏幕大小的比例都不是很大,通过设置一个合理的阈值,就可以较准确的判断出是否是软键盘显示和隐藏引起的布局变化。
此外,getWindowVisibleDisplayFrame()会返回窗口的可见区域高度,通过和屏幕高度相减,就可以得到软键盘的高度了。

监听软键盘的状态变化

在获取到软键盘的状态和高度后就可以执行需要的操作了。如重新布局按钮位置,设置变量,记录当前软键盘状态和上次软键盘隐藏时间等。不过如果有多个类需要根据软键盘状态来执行一些操作,如果每个类中都去这样做一遍就很麻烦,而且也没有必要。这时在可以自行定义一个接口,在主Activity中对软键盘状态变化进行监听,其他对软键盘状态感兴趣的类,向主Activity中注册软键盘状态变化监听。在主Activity中,当软键盘状态发生改变时通知监听者。

完整示例代码

完整的示例代码如下。

public interface OnSoftKeyboardStateChangedListener {
  public void OnSoftKeyboardStateChanged(boolean isKeyBoardShow, int keyboardHeight);
}

//注册软键盘状态变化监听
public void addSoftKeyboardChangedListener(OnSoftKeyboardStateChangedListener listener) {
  if (listener != null) {
    mKeyboardStateListeners.add(listener);
  }
}
//取消软键盘状态变化监听
public void removeSoftKeyboardChangedListener(OnSoftKeyboardStateChangedListener listener) {
  if (listener != null) {
    mKeyboardStateListeners.remove(listener);
  }
}

private ArrayList mKeyboardStateListeners;   //软键盘状态监听列表
private OnGlobalLayoutListener mLayoutChangeListener;
private boolean mIsSoftKeyboardShowing;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_login);
  mIsSoftKeyboardShowing = false;
  mKeyboardStateListeners = new ArrayList();
  mLayoutChangeListener = new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
      //判断窗口可见区域大小
      Rect r = new Rect();
      getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
      //如果屏幕高度和Window可见区域高度差值大于整个屏幕高度的1/3,则表示软键盘显示中,否则软键盘为隐藏状态。
      int heightDifference = screenHeight - (r.bottom - r.top);
      boolean isKeyboardShowing = heightDifference > screenHeight/3;

      //如果之前软键盘状态为显示,现在为关闭,或者之前为关闭,现在为显示,则表示软键盘的状态发生了改变
      if ((mIsSoftKeyboardShowing && !isKeyboardShowing) || (!mIsSoftKeyboardShowing && isKeyboardShowing)) {
        mIsSoftKeyboardShowing = isKeyboardShowing;
        for (int i = 0; i = Build.VERSION_CODES.JELLY_BEAN) {
    getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(mLayoutChangeListener);
  } else {
    getWindow().getDecorView().getViewTreeObserver().removeGlobalOnLayoutListener(mLayoutChangeListener);
  }
  super.onDestroy();
};

其中screenHeight 是屏幕高度,关于屏幕高度的获取方法,网上有很多,这里就不介绍了。

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

推荐阅读
  • 浅谈Java中String的常用方法
    今天带大家来复习一下Java中String的常用方法,文中有非常详细的介绍,对正在学习java的小伙伴们有很好的帮助,需要的朋友可以参考下 ... [详细]
  • 本篇文章给大家带来的内容是关于WebView加载优化的方法介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 ... [详细]
  • 本文用三种方法实现了在安卓上的时间获取功能,喜欢的小伙伴收藏一下,去试试吧! ... [详细]
  • 一、JSON解析之传统的JSON解析,分为以下三种情况,一个JavaBean,一个List数组,一个嵌套Map的List数组。二、JSON解析之GSON。三、JSON解析之FastJSON。 ... [详细]
  • java语言可以进行:1、Android应用开发;2、金融业应用的服务器程序开发;3、网站开发;4、软件工具开发;5、交易系统开发;6、嵌入式领域开发;7、大数据开发等等。 ... [详细]
  • JavaEE是Java平台企业版,之前称为J2EE,是Sun公司为企业级应用推出的标准平台。JavaEE可以做手机软件,JavaEE也可以做一些桌面软件,也可以用来进行网站开发。 ... [详细]
  • 许多的Android应用都是Java程序员开发者开发。Java在金融服务业的应用非常广泛,很多第三方交易系统、银行、金融机构都选择用Java开发,因为相对而言,Java较安全。 ... [详细]
  • 安卓与java的区别是:安卓是主流智能手机的操作系统,而Java是一门开发语言,从工作岗位来看,安卓从事的是移动互联方向,Java则是从事开发方向。二者的联系是:安卓应用层上的应用程序是用Java编写的,以Java作为开发语言。 ... [详细]
  • usb调试模式的作用:可在计算机和android设备之间复制数据、在移动设备上安装应用程序、读取日志数据等等。在usb调试模式下,手机只要连接电脑就相当于获得了最高控制权,读取联系人、短信、手机文件都非常方便。 ... [详细]
  • samsungpushservice中文意思为“三星推送服务”,三星app应用商店的一个后台推送服务,主要是用来推送一些通知的。samsungpushservice是手机系统软件,删除对手机系统稳定没影响。 ... [详细]
devbox
rgx-秀_550
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved PHP1.CN 第一PHP社区 版权所有 京ICP备19059560号-4