问题与解决
在 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 Windows 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 Windows itself is as big as the Windows of the Activity.
- * The keyboard can then be calculated by extracting the popup view bottom
- * from the activity Windows 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 相关博客: 我的博客地址
来源: https://www.cnblogs.com/lloyd-zh/p/9803731.html