前言
众所周知,Google并未提供用于Android的官方API来监视软键盘的弹出和关闭。通常的做法是监视“活动”窗口的布局更改,以确定是否弹出/关闭软键盘。
代码实现
应注意,此处未使用ViewTreeObserver.OnGlobalLayoutListener来监视布局,但是将打开一个子线程以进行常规检查,因为在实际生产中发现onGlobalLayout()的刷新时间不确定。这与布局的复杂性有关,有时回叫一次可能需要2/3秒,依靠它来监视窗口的变化以确定弹出/关闭小键盘是否很酷。
在这里,我们将使用RxJava打开子线程,请参阅Android Kotlin基于RxJava的简单软件包,

获取一个循环播放器以连续检查窗口的更改,并在发生更改时吐出一个事件。
IKeyBoardCallback
interface IKeyBoardCallback {
/**
* 当键盘显示时回调
*/
fun onKeyBoardShow()
/**
* 当键盘隐藏时回调
*/
fun onKeyBoardHidden()
}
GlobalLayoutListenerTask
class GlobalLayoutListenerTask(private val activity: Activity) : SingleTask(){
private val iKeyBoardCallbackList = mutableListOf()
private var status = NONE
private val interval = 100L
/** 全屏时的高度 */
private var fullScreenHeight = -1
/** 状态栏高度 */
private var statusBarHeight = -1
override fun onTaskRun() {
while (isRunning){
try {
//获取可视范围
val rect = Rect()
activity.window.decorView.getWindowVisibleDisplayFrame(rect)
//获取屏幕高度
val screenHeight = getFullScreenHeight(activity)
//获取状态栏高度
val statueHeight = getStatueBarHeight(activity)
//获取被遮挡高度(键盘高度)(屏幕高度-状态栏高度-可视范围)
val keyBoardHeight: Int = screenHeight - statusBarHeight - rect.height()
//显示或者隐藏
val isKeyBoardShow = keyBoardHeight >= screenHeight / 3
//当首次或者和之前的状态不一致的时候会回调,反之不回调(用于当状态变化后才回调,防止多次调用)
if (status == NONE || (isKeyBoardShow && status == HIDDEN) || (!isKeyBoardShow && status == SHOW)) {
if (isKeyBoardShow) {
status = SHOW
dispatchKeyBoardShowEvent()
} else {
status = HIDDEN
dispatchKeyBoardHiddenEvent()
}
}
Thread.sleep(interval)
} catch (e: Exception){
e.printStackTrace()
}
}
}
/**
* 用于获取全屏时的整体高度
*
* @return 屏幕高度
*/
private fun getFullScreenHeight(activity: Activity): Int {
if (fullScreenHeight == -1){
val vm = activity.windowManager
fullScreenHeight = vm.defaultDisplay.height
}
return fullScreenHeight
}
/**
* 用于获取状态栏高度
*
* @return 状态栏高度
*/
private fun getStatueBarHeight(activity: Activity): Int {
if (statusBarHeight == -1){
val res = activity.resources
val resId = res.getIdentifier("status_bar_height", "dimen", "android")
statusBarHeight = res.getDimensionPixelSize(resId)
}
return statusBarHeight;
}
/**
* 添加回调
*
* @param callback 的回调类
*/
fun addCallBack(callback: Any?){
if (callback is IKeyBoardCallback) iKeyBoardCallbackList.add(callback)
}
/**
* 移除回调
*
* @param callback 的回调类
*/
fun removeCallback(callback: Any?){
if (callback is IKeyBoardCallback) iKeyBoardCallbackList.remove(callback)
}
/**
* 分发隐藏事件
*/
private fun dispatchKeyBoardHiddenEvent(){
for (callback in iKeyBoardCallbackList){
callback.onKeyBoardHidden()
}
}
/**
* 分发显示事件
*/
private fun dispatchKeyBoardShowEvent(){
for (callback in iKeyBoardCallbackList){
callback.onKeyBoardShow()
}
}
/**
* 判断是不是没有回调
*
* @return true:空 false:不空
*/
fun isEmpty(): Boolean = iKeyBoardCallbackList.isEmpty()
companion object {
private const val NONE = 0;
private const val SHOW = 1;
private const val HIDDEN = 2;
}
}
KeyBoardEventBus
object KeyBoardEventBus {
private val taskCache: Hashtable = Hashtable()
/**
* 用于注册键盘,此方法适用于 View、Dialog、Fragement、FragementActivity、Activity
*
* @param obj 需要的类()
*/
fun register(obj: Any?){
val activity = getActivity(obj)
if (activity == null){
debug("register时获取activity失败!")
return
}
register(activity, obj)
}
/**
* 此方法区别于 {@link #register(Object)} ,之前的方法会限制注册的类型,当前的不会限制类型
*
* @param activity 宿主activity
* @param obj 的类
*/
fun register(activity: Activity, obj: Any?){
if (obj == null) {
debug("object为null!")
return
}
var task = taskCache[activity]
if (task == null){
task = GlobalLayoutListenerTask(activity)
}
task.addCallBack(obj)
if (!task.isEmpty()) task.start()
taskCache[activity] = task
}
/**
* 反注册
*
* @param obj 取消的类
*/
fun unRegister(obj: Any?){
//获取失败则直接停止,反之进行反注册
val activity = getActivity(obj)
if (activity == null){
debug("unRegister时获取activity失败")
return
}
unRegister(activity, obj)
}
/**
* 反注册
*
* @param activity 宿主activity
* @param obj 的类
*/
fun unRegister(activity: Activity, obj: Any?){
if ( obj == null) {
debug("activity或object为null!")
return
}
val task = taskCache[activity] ?: return
task.removeCallback(obj)
if (task.isEmpty()){
task.cancel()
taskCache.remove(task)
}
}
/**
* 获取对应View、Dialog、Fragment、FragmentActivity、Activity
* (如果Object为null或者不是支持的类型则返回null)
*
* @param obj 需要获取的类
* @return 返回对应的activity
*/
private fun getActivity(obj: Any?): Activity?{
if (obj == null) return null
return when(obj){
is View -> obj.context as Activity
is Dialog -> obj.context as Activity
is Fragment -> obj.activity
is FragmentActivity -> obj
is Activity -> obj
else -> null
}
}
/**
* 用于打印信息
*
* @param msg 待打印的内容
*/
private fun debug(msg: String){
Log.e("KeyBoardEventBus",msg)
}
}
用法

有关postUI,请参阅Android Kotlin代码说明,全局UI线程回调函数(基于扩展函数)
用于回调UI线程播放Toast
class MainActivity : AppCompatActivity(),IKeyBoardCallback {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
KeyBoardEventBus.register(this)
}
override fun onDestroy() {
super.onDestroy()
KeyBoardEventBus.unRegister(this)
}
override fun onKeyBoardShow() {
postUI {
Toast.makeText(this, "键盘显示",Toast.LENGTH_SHORT).show()
}
}
override fun onKeyBoardHidden() {
postUI {
Toast.makeText(this, "键盘隐藏",Toast.LENGTH_SHORT).show()
}
}
}
完成工作
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/bofangqi/article-374201-1.html
如同2楼这种贪生怕死的人多半会是汉奸
肯定是这只学生放入去的