问题与解决

在Android应用的开发中,有一些需求需要我们获取到输入法的高度,但是官方的API并没有提供类似的方法,所以我们需要自己来实现。

查阅了网上很多资料,试过以后都不理想。

比如有的方法通过监听布局的变化来计算输入法的高度,这种方式在Activity的配置中配置为"android:windowSoftInputMode="adjustResize""时没有问题,可以正确获取输入法的高度,因为布局此时确实会动态的调整。

但是当Activity配置为"android:windowSoftInputMode="adjustNothing""时,布局不会在输入法弹出时进行调整,上面的方式就会扑街。

不过经过一番探索和测试,终于发现了一种方式可以在即使设置为adjustNothing时也可以正确计算高度放方法。

同时也感谢这位外国朋友:

GitHub地址

其实也就两个类,我也做了一些修改,解决了一些问题,这里也贴出来:

  • KeyboardHeightObserver.java
/**
* The observer that will be notified when the height of
* the keyboard has changed
*/
public interface KeyboardHeightObserver { /**
* Called when the keyboard height has changed, 0 means keyboard is closed,
* >= 1 means keyboard is opened.
*
* @param height The height of the keyboard in pixels
* @param orientation The orientation either: Configuration.ORIENTATION_PORTRAIT or
* Configuration.ORIENTATION_LANDSCAPE
*/
void onKeyboardHeightChanged(int height, int orientation);
}
  • KeyboardHeightProvider.java
/**
* The keyboard height provider, this class uses a PopupWindow
* to calculate the window height when the floating keyboard is opened and closed.
*/
public class KeyboardHeightProvider extends PopupWindow { /** The tag for logging purposes */
private final static String TAG = "sample_KeyboardHeightProvider"; /** The keyboard height observer */
private KeyboardHeightObserver observer; /** The cached landscape height of the keyboard */
private int keyboardLandscapeHeight; /** The cached portrait height of the keyboard */
private int keyboardPortraitHeight; /** The view that is used to calculate the keyboard height */
private View popupView; /** The parent view */
private View parentView; /** The root activity that uses this KeyboardHeightProvider */
private Activity activity; /**
* Construct a new KeyboardHeightProvider
*
* @param activity The parent activity
*/
public KeyboardHeightProvider(Activity activity) {
super(activity);
this.activity = activity; LayoutInflater inflator = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
this.popupView = inflator.inflate(R.layout.keyboard_popup_window, null, false);
setContentView(popupView); setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_RESIZE | LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); parentView = activity.findViewById(android.R.id.content); setWidth(0);
setHeight(LayoutParams.MATCH_PARENT); popupView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override
public void onGlobalLayout() {
if (popupView != null) {
handleOnGlobalLayout();
}
}
});
} /**
* Start the KeyboardHeightProvider, this must be called after the onResume of the Activity.
* PopupWindows are not allowed to be registered before the onResume has finished
* of the Activity.
*/
public void start() { if (!isShowing() && parentView.getWindowToken() != null) {
setBackgroundDrawable(new ColorDrawable(0));
showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0);
}
} /**
* Close the keyboard height provider,
* this provider will not be used anymore.
*/
public void close() {
this.observer = null;
dismiss();
} /**
* Set the keyboard height observer to this provider. The
* observer will be notified when the keyboard height has changed.
* For example when the keyboard is opened or closed.
*
* @param observer The observer to be added to this provider.
*/
public void setKeyboardHeightObserver(KeyboardHeightObserver observer) {
this.observer = observer;
} /**
* Get the screen orientation
*
* @return the screen orientation
*/
private int getScreenOrientation() {
return activity.getResources().getConfiguration().orientation;
} /**
* Popup window itself is as big as the window of the Activity.
* The keyboard can then be calculated by extracting the popup view bottom
* from the activity window height.
*/
private void handleOnGlobalLayout() { Point screenSize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(screenSize); Rect rect = new Rect();
popupView.getWindowVisibleDisplayFrame(rect); // REMIND, you may like to change this using the fullscreen size of the phone
// and also using the status bar and navigation bar heights of the phone to calculate
// the keyboard height. But this worked fine on a Nexus.
int orientation = getScreenOrientation();
int keyboardHeight = screenSize.y - rect.bottom; if (keyboardHeight == 0) {
notifyKeyboardHeightChanged(0, orientation);
}
else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
this.keyboardPortraitHeight = keyboardHeight;
notifyKeyboardHeightChanged(keyboardPortraitHeight, orientation);
}
else {
this.keyboardLandscapeHeight = keyboardHeight;
notifyKeyboardHeightChanged(keyboardLandscapeHeight, orientation);
}
} private void notifyKeyboardHeightChanged(int height, int orientation) {
if (observer != null) {
observer.onKeyboardHeightChanged(height, orientation);
}
}
}

使用方法

此处以在Activity中的使用进行举例。

实现接口

引入这两个类后,在当前Activity中实现接口KeyboardHeightObserver:

@Override
public void onKeyboardHeightChanged(int height, int orientation) {
String or = orientation == Configuration.ORIENTATION_PORTRAIT ? "portrait" : "landscape";
Logger.d(TAG, "onKeyboardHeightChanged in pixels: " + height + " " + or);
}

定义并初始化

在当前Activity定义成员变量,并在onCreate()中进行初始化

private KeyboardHeightProvider mKeyboardHeightProvider;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
mKeyboardHeightProvider = new KeyboardHeightProvider(this);
new Handler().post(() -> mKeyboardHeightProvider.start());
}

生命周期处理

初始化完成后,我们要在Activity中的生命周期中也要进行处理,以免内存泄露。

@Override
protected void onResume() {
super.onResume();
mKeyboardHeightProvider.setKeyboardHeightObserver(this);
} @Override
protected void onPause() {
super.onPause();
mKeyboardHeightProvider.setKeyboardHeightObserver(null);
} @Override
protected void onDestroy() {
super.onDestroy();
mKeyboardHeightProvider.close();
}

总结

此时我们就可以正确获取的当前输入法的高度了,即使android:windowSoftInputMode="adjustNothing"时也可以正确获取到,这正是这个方法的强大之处,利用这个方法可以实现比如类似微信聊天的界面,流畅切换输入框,表情框等。

如有更多疑问,请参考我的其它Android相关博客:我的博客地址

Android开发 - 获取系统输入法高度的正确姿势的更多相关文章

  1. Android开发 - 获取Android设备的唯一标识码(Android 6.0或更高)

    在我们的APP开发中,通常需要获取到设备的唯一标识.在Android6.0之前,有很多方法我们可以方便获取到硬件的唯一标识,但是在Android6.0之后,Android系统大幅限制了我们获取设备的硬 ...

  2. android开发中系统自带语音模块的使用

    android开发中系统自带语音模块的使用需求:项目中需要添加语音搜索模块,增加用户体验解决过程:在网上搜到语音搜索例子,参考网上代码,加入到了自己的项目,完成产品要求.这个问题很好解决,网上能找到很 ...

  3. android开发获取网络状态,wifi,wap,2g,3g.工具类(一)

    android开发获取网络状态整理: package com.gzcivil.utils; import android.content.Context; import android.net.Con ...

  4. Android中获取系统上安装的APP信息

    Version:0.9 StartHTML:-1 EndHTML:-1 StartFragment:00000099 EndFragment:00003259 Android中获取系统上安装的APP信 ...

  5. 基于jeesite+android开发 电子商务系统免费教程

    下载地址: jeesite免费教程 基于jeesite+android开发 电子商务系统免费教程 基于jeesite+android开发 电子商务系统免费教程 这个教程已经录制完很久了,一直没有公开, ...

  6. Android 开发 获取Android设备的屏幕高宽

    获得屏幕的宽度和高度有很多种方法: //1.通过WindowManager获取 DisplayMetrics dm = new DisplayMetrics(); heigth = dm.height ...

  7. android:sharedUserId 获取系统权限

    最近在做的项目,有好大一部分都用到这个权限,修改系统时间啊,调用隐藏方法啊,系统关机重启啊,静默安装升级卸载应用等等,刚开始的时候,直接添加权限,运行就报错,无论模拟器还是真机,在logcat中总会得 ...

  8. Android apk获取系统权限

    Android在apk内部,即通过java代码来进行修改系统文件或者修改系统设置等等,这样需要获取系统权限. 通过直接配置apk运行在System进程内 1. 在应用程序的AndroidManifes ...

  9. Android项目--获取系统通讯录列表

    ----------------- 通讯录列表 ----------------- 按常理来说,获取系统通讯录列表,无非就是将通讯录的数据库打开获取数据,适配,添加即可. Cursor cursor; ...

随机推荐

  1. 解决mysql安装出现error Nr.1045问题

    我们在windows下安装mysql最后一步时会出现Access denied for user 'root'@localhost'(using password:No)的问题.这几个问题经常出现在卸 ...

  2. 【算法】BFS+哈希解决八数码问题

    15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖“X”; 拼图的目的是安排 ...

  3. Android Makefile中是 如何识别 TARGET_PRODUCT 的

    http://blog.csdn.net/stevenliyong/article/details/5285334 今天有时间小看一下Android 的Makefile, 终于稍有明白Android ...

  4. PHP字符串位置相关的函数

    strpos函数 描述:将返回一个字符串在另一个字符串第一次出现的位置 语法:int strpos(string haystack, mixed needle [,int offset]); 相反地 ...

  5. IDEA将项目导出war包方法(详细)

    右上角点击进入配置页面(如图)选择Artifcts 点击绿色的那个+号,选择Web Application:Archive; 设置名称,选择输出路径 下面开始打war包在Build下面选择Build ...

  6. Windows下python环境配置

    步骤: 1.安装Python.Sublime Text: 2.打开Sublime Text,在菜单栏点击“Tools”->“Build System”->“New Build System ...

  7. vue的过渡和动画

    简单过渡 .fade-enter-active, .fade-leave-active { transition: all .5s; } /*.fade-enter, .fade-leave-to { ...

  8. mouseover和mouseout事件的相关元素

    在发生mouseover和mouseout事件时,还会涉及更多的元素,这两个事件都会涉及把鼠标指针从一个元素的边界之内移动到另一个元素的边界之内.对mouseover事件而言,事件的主目标获得光标元素 ...

  9. 避免使用eval()

    eval()可以将任意的字符串当做一个JavaScript代码来执行. eval()使用实例: // 烦模式 var property = 'name'; console.log(eval('obj. ...

  10. VSCode的终端修改

    快速打开VSCode的快捷键是:Ctrl + `(反引号) 转自:https://blog.csdn.net/u013517122/article/details/82776607 因本人实在忍受不了 ...