之前写过一个监听Android系统软键盘高度的解决方案——软键盘高度监测最佳实践,今天将这个方案加以改进,写成了一个库——skb-global。
一、安装
该库托管于jitpack,所以在使用前,请先引入jitpack。
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
然后添加依赖。
dependencies {
implementation 'com.github.boybeak:skb-global:Tag'
}
最新版本为:
二、使用
有两种使用方式:全局和局部。
2.1 全局使用
在使用前,需要先在Application中初始化SoftKeyboardGlobal
。
class App : Application() {
override fun onCreate() {
super.onCreate()
SoftKeyboardGlobal.install(this, true)
}
}
其中,第二个参数传入
true
,可以在UI界面显示一个高度指示器。
然后,在你应用中的任意位置,可以监听键盘的状态与高度,如下方式:
SoftKeyboardGlobal.addSoftKeyboardCallback(object : SoftKeyboardGlobal.SoftKeyboardCallback {
override fun onOpen(height: Int) {
Log.d(TAG, "onOpen height=$height")
}
override fun onClose() {
Log.d(TAG, "onClose")
}
override fun onHeightChanged(height: Int) {
Log.d(TAG, "onHeightChanged height=$height")
}
})
2.2 局部使用
你可以在任意Activity
, Fragment
或者View
中使用这种方式,只要能获取到Activity
实例。以Activity
为例,如下方式:
class MainActivity : AppCompatActivity() {
private val observer by lazy { KeyboardObserver.create(this, true) }
private val switchBtn: SwitchCompat by lazy { findViewById(R.id.switchBtn) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
switchBtn.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
observer.watch()
} else {
observer.unwatch()
}
}
}
}
同样的,在创建KeyboardObserver
时,第二个参数传入true
可以显示一个键盘高度指示器,方便调试。
三、原理分析
该方案是在多年开发过程中,实践出来的最佳的方案。以前的旧方案,实现方式如下:
- 在界面中放置一个测量布局,然后监听布局变化,但是布局尺寸变化,有可能会执行多次,很难判断键盘的高度是什么时候停止变化的;
- 为了解决这个问题,我放置了一个延迟触发任务,只要布局变化就取消上一个任务,并且布置一个新的延迟任务,等到布局不再发生变化,就会存留最后一个放置的任务被触发了,再获取测量布局高度,计算与总高度的差值。
这种旧方案的缺点很多,比如:
- 侵入性,必须在布局中显式的放置测量布局;
- 滞后性,测量时机上延迟的,并不能在布局稳定的第一时间获取到键盘的高度;
- 误触性,由于获取键盘高度靠延迟任务,延迟的时间太长,则导致滞后性太严重,太短,则可能来不及取消上一个任务,测量高度就被错误触发;
- 不定性,由于设备可能会有横竖屏幕切换,因横竖屏切换导致的测量布局尺寸发生变化进而触发键盘高度事件,这个是不可接受的。
为了解决这些问题,进而开发出这个方案,简单阐述一下原理。
新的方案使用了两个隐藏的PopupWindow
,一个用于测量屏幕的总高度,称为Ruler——尺子,另外一个用于跟随软键盘的弹起/收回而进行伸缩,称为Cursor——游标。
这样做,可以避免侵入。
- 低侵入性,只需要调用watch与unwatch即可;
- 无滞后性,由于不采用延迟任务的方式,所以没有滞后性;
- 无误触性,同样是因为没有采用延迟任务的方式,所以没有误触性;
- 稳定性,由于采用的是双布局的差值比较,所以不会因为横竖屏幕切换导致的触发键盘高度事件;
想要更多细节,请查看代码:skb-global。