一、获取软键盘高度之方式一

要说获取软键盘的高度,那么肯定离不开 getViewTreeObserver().addOnGlobalLayoutListener 的方式。
只是使用起来又分不同的做法,最简单的是拿到Activity的ContentView,设置
contentView.getViewTreeObserver() .addOnGlobalLayoutListener(onGlobalLayoutListener);
然后在监听内部再通过 decorView.getWindowVisibleDisplayFrame来获取显示的Rect,在通过 decorView.getBottom() - outRect.bottom的方式来获取高度。
完整示例如下:

public final class Keyboard1Utils {public static int sDecorViewInvisibleHeightPre;private static ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener;private static int mNavHeight;private Keyboard1Utils() {}private static int sDecorViewDelta = 0;private static int getDecorViewInvisibleHeight(final Activity activity) {final View decorView = activity.getWindow().getDecorView();if (decorView == null) return sDecorViewInvisibleHeightPre;final Rect outRect = new Rect();decorView.getWindowVisibleDisplayFrame(outRect);int delta = Math.abs(decorView.getBottom() - outRect.bottom);if (delta <= mNavHeight) {sDecorViewDelta = delta;return 0;}return delta - sDecorViewDelta;}public static void registerKeyboardHeightListener(final Activity activity, final KeyboardHeightListener listener) {final int flags = activity.getWindow().getAttributes().flags;if ((flags & WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) != 0) {activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);}final FrameLayout contentView = activity.findViewById(android.R.id.content);sDecorViewInvisibleHeightPre = getDecorViewInvisibleHeight(activity);onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {int height = getDecorViewInvisibleHeight(activity);if (sDecorViewInvisibleHeightPre != height) {listener.onKeyboardHeightChanged(height);sDecorViewInvisibleHeightPre = height;}}};//获取到导航栏高度之后再添加布局监听getNavigationBarHeight(activity, new NavigationBarCallback() {@Overridepublic void onHeight(int height, boolean hasNav) {mNavHeight = height;contentView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);}});}public static void unregisterKeyboardHeightListener(Activity activity) {onGlobalLayoutListener = null;View contentView = activity.getWindow().getDecorView().findViewById(android.R.id.content);if (contentView == null) return;contentView.getViewTreeObserver().removeGlobalOnLayoutListener(onGlobalLayoutListener);}private static int getNavBarHeight() {Resources res = Resources.getSystem();int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");if (resourceId != 0) {return res.getDimensionPixelSize(resourceId);} else {return 0;}}public static void getNavigationBarHeight(Activity activity, NavigationBarCallback callback) {View view = activity.getWindow().getDecorView();boolean attachedToWindow = view.isAttachedToWindow();if (attachedToWindow) {WindowInsetsCompat windowInsets = ViewCompat.getRootWindowInsets(view);assert windowInsets != null;int height = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;boolean hasNavigationBar = windowInsets.isVisible(WindowInsetsCompat.Type.navigationBars()) &&windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0;if (height > 0) {callback.onHeight(height, hasNavigationBar);} else {callback.onHeight(getNavBarHeight(), hasNavigationBar);}} else {view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {@Overridepublic void onViewAttachedToWindow(View v) {WindowInsetsCompat windowInsets = ViewCompat.getRootWindowInsets(v);assert windowInsets != null;int height = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;boolean hasNavigationBar = windowInsets.isVisible(WindowInsetsCompat.Type.navigationBars()) &&windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0;if (height > 0) {callback.onHeight(height, hasNavigationBar);} else {callback.onHeight(getNavBarHeight(), hasNavigationBar);}}@Overridepublic void onViewDetachedFromWindow(View v) {}});}}public interface KeyboardHeightListener {void onKeyboardHeightChanged(int height);}
}

使用:

    override fun init() {Keyboard1Utils.registerKeyboardHeightListener(this) {YYLogUtils.w("当前的软键盘高度:$it")}
}

需要注意的是方法内部获取导航栏的方法是过时的,部分手机会有问题,但是并没有用它做计算,只是用于一个Flag,终归还是能用,经过我的测试也并不会影响效果。

二、获取软键盘高度之方式二

获取软键盘高度的第二种方式也是使用 getViewTreeObserver().addOnGlobalLayoutListener 的方式,不过不同的是,它是在Activity添加了一个PopupWindow,然后让软键盘弹起的时候,计算PopopWindow移动了多少范围,从而计算软键盘的高度。

它创建一个看不见的弹窗,即宽为0,高为全屏,并为弹窗设置全局布局监听器。当布局有变化,比如有输入法弹窗出现或消失时, 监听器回调函数就会被调用。而其中的关键就是当输入法弹出时, 它会把之前我们创建的那个看不见的弹窗往上挤, 这样我们创建的那个弹窗的位置就变化了,只要获取它底部高度的变化值就可以间接的获取输入法的高度了。
这里我对源码做了一点修改

public class KeyboardHeightUtils extends PopupWindow {private KeyboardHeightListener mListener;private View popupView;private View parentView;private Activity activity;public KeyboardHeightUtils(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(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);parentView = activity.findViewById(android.R.id.content);setWidth(0);setHeight(WindowManager.LayoutParams.MATCH_PARENT);popupView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {if (popupView != null) {handleOnGlobalLayout();}}});}public void start() {parentView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {@Overridepublic void onViewAttachedToWindow(View view) {if (!isShowing() && parentView.getWindowToken() != null) {setBackgroundDrawable(new ColorDrawable(0));showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0);}}@Overridepublic void onViewDetachedFromWindow(View view) {}});}public void close() {this.mListener = null;dismiss();}public void registerKeyboardHeightListener(KeyboardHeightListener listener) {this.mListener = listener;}private void handleOnGlobalLayout() {Point screenSize = new Point();activity.getWindowManager().getDefaultDisplay().getSize(screenSize);Rect rect = new Rect();popupView.getWindowVisibleDisplayFrame(rect);int keyboardHeight = screenSize.y - rect.bottom;notifyKeyboardHeightChanged(keyboardHeight);}private void notifyKeyboardHeightChanged(int height) {if (mListener != null) {mListener.onKeyboardHeightChanged(height);}}public interface KeyboardHeightListener {void onKeyboardHeightChanged(int height);}}

使用的方式:

    override fun init() {keyboardHeightUtils = KeyboardHeightUtils(this)keyboardHeightUtils.registerKeyboardHeightListener {YYLogUtils.w("第二种方式:当前的软键盘高度:$it")}keyboardHeightUtils.start()}override fun onDestroy() {super.onDestroy()Keyboard1Utils.unregisterKeyboardHeightListener(this)keyboardHeightUtils.close();}

和第一种方案有异曲同工之妙,都是一个方法,但是思路有所不同,但是这种方法也有一个坑点,就是需要计算状态栏的高度。可以看到第二种方案和第一种方案有一个状态栏高度的偏差,大家记得处理即可。

三、获取软键盘高度之方式三

如果能直接使用兼容方案,那肯定是完美的:

    ViewCompat.setWindowInsetsAnimationCallback(window.decorView, object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {override fun onProgress(insets: WindowInsetsCompat, runningAnimations: MutableList<WindowInsetsAnimationCompat>): WindowInsetsCompat {val isVisible = insets.isVisible(WindowInsetsCompat.Type.ime())val keyboardHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom//当前是否展示YYLogUtils.w("isVisible = $isVisible")//当前的高度进度回调YYLogUtils.w("keyboardHeight = $keyboardHeight")return insets}})ViewCompat.getWindowInsetsController(findViewById(android.R.id.content))?.apply {show(WindowInsetsCompat.Type.ime())}

可惜想法很好,实际上也只有在Android R 以上才好用,低版本要么就只触发一次,要么就干脆不触发。兼容性的方案也有兼容性问题!

我们需要在Android11上使用动画监听的方案,而Android11一下使用 setOnApplyWindowInsetsListener 的方式来获取。

代码大概如下

    fun addKeyBordHeightChangeCallBack(view: View, onAction: (height: Int) -> Unit) {var posBottom: Intif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {val cb = object : WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {override fun onProgress(insets: WindowInsets,animations: MutableList<WindowInsetsAnimation>): WindowInsets {posBottom = insets.getInsets(WindowInsets.Type.ime()).bottom +insets.getInsets(WindowInsets.Type.systemBars()).bottomonAction.invoke(posBottom)return insets}}view.setWindowInsetsAnimationCallback(cb)} else {ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->posBottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom +insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottomonAction.invoke(posBottom)insets}}}

但是实测之后发现,就算是兼容版本的 setOnApplyWindowInsetsListener 方法,获取状态栏和导航栏没有问题,但是当软键盘弹起和收起的时候并不会再次回调,也就是部分设备和版本只能调用一次,再次弹软键盘的时候就不触发了。

如果觉得不保险大家也可以在控件上屏之后再设置监听,onResume中设置监听,这样确保是设置监听成功,在Android11以上的设备,使用兼容方案的监听是可以拿到监听,Android11以下的设备有些也可以拿到监听。

所以我们如果想兼容版本的话,那没办法了,只能出绝招了,我们就把 Android11 以下的机型使用 getViewTreeObserver().addOnGlobalLayoutListener 的方式,而 Android11 以上的我们使用 WindowInsets 的方案,这样就是最为保险的方式。
具体的兼容方案如下:

public final class Keyboard4Utils {public static int sDecorViewInvisibleHeightPre;private static ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener;private static int mNavHeight;private Keyboard4Utils() {}private static int sDecorViewDelta = 0;private static int getDecorViewInvisibleHeight(final Activity activity) {final View decorView = activity.getWindow().getDecorView();if (decorView == null) return sDecorViewInvisibleHeightPre;final Rect outRect = new Rect();decorView.getWindowVisibleDisplayFrame(outRect);int delta = Math.abs(decorView.getBottom() - outRect.bottom);if (delta <= mNavHeight) {sDecorViewDelta = delta;return 0;}return delta - sDecorViewDelta;}public static void registerKeyboardHeightListener(final Activity activity, final KeyboardHeightListener listener) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {invokeAbove31(activity, listener);} else {invokeBelow31(activity, listener);}}@RequiresApi(api = Build.VERSION_CODES.R)private static void invokeAbove31(Activity activity, KeyboardHeightListener listener) {activity.getWindow().getDecorView().setWindowInsetsAnimationCallback(new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {@NonNull@Overridepublic WindowInsets onProgress(@NonNull WindowInsets windowInsets, @NonNull List<WindowInsetsAnimation> list) {int imeHeight = windowInsets.getInsets(WindowInsetsCompat.Type.ime()).bottom;int navHeight = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;boolean hasNavigationBar = windowInsets.isVisible(WindowInsetsCompat.Type.navigationBars()) &&windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0;listener.onKeyboardHeightChanged(hasNavigationBar ? Math.max(imeHeight - navHeight, 0) : imeHeight);return windowInsets;}});}private static void invokeBelow31(Activity activity, KeyboardHeightListener listener) {final int flags = activity.getWindow().getAttributes().flags;if ((flags & WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) != 0) {activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);}final FrameLayout contentView = activity.findViewById(android.R.id.content);sDecorViewInvisibleHeightPre = getDecorViewInvisibleHeight(activity);onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {int height = getDecorViewInvisibleHeight(activity);if (sDecorViewInvisibleHeightPre != height) {listener.onKeyboardHeightChanged(height);sDecorViewInvisibleHeightPre = height;}}};//获取到导航栏高度之后再添加布局监听getNavigationBarHeight(activity, new NavigationBarCallback() {@Overridepublic void onHeight(int height, boolean hasNav) {mNavHeight = height;contentView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);}});}public static void unregisterKeyboardHeightListener(Activity activity) {onGlobalLayoutListener = null;View contentView = activity.getWindow().getDecorView().findViewById(android.R.id.content);if (contentView == null) return;contentView.getViewTreeObserver().removeGlobalOnLayoutListener(onGlobalLayoutListener);}private static int getNavBarHeight() {Resources res = Resources.getSystem();int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");if (resourceId != 0) {return res.getDimensionPixelSize(resourceId);} else {return 0;}}public static void getNavigationBarHeight(Activity activity, NavigationBarCallback callback) {View view = activity.getWindow().getDecorView();boolean attachedToWindow = view.isAttachedToWindow();if (attachedToWindow) {WindowInsetsCompat windowInsets = ViewCompat.getRootWindowInsets(view);assert windowInsets != null;int height = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;boolean hasNavigationBar = windowInsets.isVisible(WindowInsetsCompat.Type.navigationBars()) &&windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0;if (height > 0) {callback.onHeight(height, hasNavigationBar);} else {callback.onHeight(getNavBarHeight(), hasNavigationBar);}} else {view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {@Overridepublic void onViewAttachedToWindow(View v) {WindowInsetsCompat windowInsets = ViewCompat.getRootWindowInsets(v);assert windowInsets != null;int height = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;boolean hasNavigationBar = windowInsets.isVisible(WindowInsetsCompat.Type.navigationBars()) &&windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0;if (height > 0) {callback.onHeight(height, hasNavigationBar);} else {callback.onHeight(getNavBarHeight(), hasNavigationBar);}}@Overridepublic void onViewDetachedFromWindow(View v) {}});}}public interface KeyboardHeightListener {void onKeyboardHeightChanged(int height);}
}

来自:https://juejin.cn/post/7150453629021847566

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:
一、面试合集

二、源码解析合集

三、开源框架合集

欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取

Android软键盘高度控制的几种方案相关推荐

  1. 获取android软键盘高度

    获取android软键盘高度,虽然是在网上找的方法,不过已亲自测试过,这方法转载太多了,不知道谁是原著了,原作者莫怪.感谢原作者. MainActivity.java public class Mai ...

  2. Android 软键盘显示隐藏判断

    Android软键盘始终感觉是个BUG,难缠 用起来不顺手,每次应用版本涉及到相关问题,总是很尴尬 只能静下心好好梳理一下 1. 软键盘显示原理 软键盘的本质是什么?软键盘其实是一个Dialog In ...

  3. android自定义键盘遮挡,Android软键盘遮挡的四种完美解决方案

    一.问题概述 在编辑框输入内容时会弹出软键盘,而手机屏幕区域有限往往会遮住输入界面,我们先看一下问题效果图: 输入用户名和密码时,系统会弹出键盘,造成系统键盘会挡住文本框的问题,如图所示: 输入密码时 ...

  4. 5种方法完美解决android软键盘挡住输入框方法详解

    版权声明:本文为CSDN博主「潇潇凤儿」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/smileiam/ ...

  5. Android软键盘遮挡的四种解决方案

    Android软键盘遮挡的四种解决方案 参考文章: (1)Android软键盘遮挡的四种解决方案 (2)https://www.cnblogs.com/jerehedu/p/4194125.html ...

  6. android获得键盘高度,Android获取软键盘高度

    在 Android 里我们是无法直接获取软键盘高度的,但是在某些场景下,我们又需要获取软键盘的高度.我们可以使用 ViewTreeObserver.OnGlobalLayoutListener来监听窗 ...

  7. android 软件盘未弹出如何获取高度,Android 软键盘的那些坑,一招搞定!

    3 软键盘高度获取 对于上面的问题1,既然想要EditText单独顶上去,那么就需要知道当前键盘弹出的高度,再设置EditText坐标即可. 问题的关键转变为如何获取键盘的高度. Activity窗口 ...

  8. Android软键盘的显示与隐藏

    本文仅是对原创文章重新进行或多或少的代码测试,权当记录并加深印象 再次感谢开发者社区的分享 一:简述 点击文本框EditText,系统会自动弹出软键盘(其本质是一个Dialog),这必然会引起当前Ac ...

  9. Android软键盘调用及隐藏,以及获得点击软键盘输入的字母信息

    在Android提供的EditText中单击的时候,会自动的弹出软键盘,其实对于软键盘的控制我们可以通过InputMethodManager这个类来实现.我们需要控制软键盘的方式就是两种一个是像Edi ...

最新文章

  1. oracle glogin.sql sql _user,为什么我的login.sql不执行?
  2. Window环境下配置MySQL 5.6的主从复制、备份恢复
  3. 全球及中国新能源汽车产业应用现状与运营前景规划报告2022版
  4. 如何机智的弄坏一台电脑?
  5. 【转】Windows编程之hdc和hwnd的区别
  6. python自定义安装哪些不需要_【1】python模块:自定义模块的3种导入方式
  7. 什么是数字孪生体?来自西门子、PTC、北航的精华观点和实践
  8. stm32寄存器版学习笔记04 定时计数器中断
  9. 邻接矩阵实现无向图的创建并根据louvain算法实现分区
  10. 学习笔记75—方差分析(主效应和交互效应)
  11. 摄像头直播视频接口视频播放器
  12. codeforces gym101482 J Judging Troubles 暴力+map
  13. 【教程】利用github学生认证免费使用CLion一年
  14. ITK入门教程(12)点集之得到存储的点
  15. 智能名片如何在会场营销落地
  16. 时间序列分析教程(一):基本性质
  17. 读书笔记——寻找道德
  18. sqlite数据库下载安装和初步操作和所遇到的问题near sqlite3:syntax error
  19. Google Earth Engine(GEE)——Landsat 8TI/TOA/SR影像对比分析区别和去云即NDVI计算
  20. 基于lifekeeper+windows 2000 + sqlserver2000 + 镜像磁盘陈列的双机热备

热门文章

  1. win10系统更新完不能开机怎么办【系统天地】
  2. windows下最强大的SSH连接软件
  3. vue纵向表头通俗易懂
  4. 鸿蒙系统和小米系统区别,华为鸿蒙系统对比小米MIUI12,到底谁更强!
  5. 产品经理Axture高保真原型设计
  6. 使用python爬取马蜂窝游记
  7. 【新词发现】基于SNS的文本数据挖掘、短语挖掘
  8. HTML核心(1)- 第一个网页
  9. 科罗拉多矿业大学计算机科学专业,科罗拉多矿业大学有哪些专业_专业排名(TFE美国大学排名)...
  10. 树莓派mqtt连接onenet平台实现消息订阅与发布