之前写过一个监听Android系统软键盘高度的解决方案——软键盘高度监测最佳实践,今天将这个方案加以改进,写成了一个库——skb-global

gif

一、安装

该库托管于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'
}

最新版本为:version

二、使用

有两种使用方式:全局局部

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可以显示一个键盘高度指示器,方便调试。

三、原理分析

该方案是在多年开发过程中,实践出来的最佳的方案。以前的旧方案,实现方式如下:

  1. 在界面中放置一个测量布局,然后监听布局变化,但是布局尺寸变化,有可能会执行多次,很难判断键盘的高度是什么时候停止变化的;
  2. 为了解决这个问题,我放置了一个延迟触发任务,只要布局变化就取消上一个任务,并且布置一个新的延迟任务,等到布局不再发生变化,就会存留最后一个放置的任务被触发了,再获取测量布局高度,计算与总高度的差值。

这种旧方案的缺点很多,比如:

  1. 侵入性,必须在布局中显式的放置测量布局;
  2. 滞后性,测量时机上延迟的,并不能在布局稳定的第一时间获取到键盘的高度;
  3. 误触性,由于获取键盘高度靠延迟任务,延迟的时间太长,则导致滞后性太严重,太短,则可能来不及取消上一个任务,测量高度就被错误触发;
  4. 不定性,由于设备可能会有横竖屏幕切换,因横竖屏切换导致的测量布局尺寸发生变化进而触发键盘高度事件,这个是不可接受的。

为了解决这些问题,进而开发出这个方案,简单阐述一下原理。 新的方案使用了两个隐藏的PopupWindow,一个用于测量屏幕的总高度,称为Ruler——尺子,另外一个用于跟随软键盘的弹起/收回而进行伸缩,称为Cursor——游标。 这样做,可以避免侵入。

  1. 低侵入性,只需要调用watch与unwatch即可;
  2. 无滞后性,由于不采用延迟任务的方式,所以没有滞后性;
  3. 无误触性,同样是因为没有采用延迟任务的方式,所以没有误触性;
  4. 稳定性,由于采用的是双布局的差值比较,所以不会因为横竖屏幕切换导致的触发键盘高度事件;

想要更多细节,请查看代码:skb-global