Open mm-longcheng opened 3 years ago
使用PopupWindow辅助监听来将主视图设为adjustNothing,确实是个好方法。 onGlobalLayout 的判断经过我使用多种真机测试,发现需要做很多无效性判定。不然很容易产生误判。
1.横屏模式在切入后台,再切回前台,部分手机会产生视图旋转。触发布局调整。 2.底部导航栏状态变更会触发布局调整。 3.有些时候我们并不会把app设置为全屏,计算键盘高度并不总等于物理高减可视底。 4.有些机型点开软键盘后会频繁触发onGlobalLayout。
这个是我自己使用的一个,可以参考一下。 https://bitbucket.org/mm_longcheng/mm-core/src/dev/nwsi/proj/android/src/org/mm/nwsi/mmUIViewLayoutListener.java
谢谢,目前工作较忙,有空会优化这些bug
请问全屏状态下键盘高度该如何获取呢
微信这个功能刚出来的时候,我也研究过它的键盘表情切换动画,这里我给出我的实现键盘高度计算的方法,目前没发现有兼容性问题 @FreddyChen
class KeyboardChangeMonitor(
private val context: Context,
private val parentView: View
) : PopupWindow(context), ViewTreeObserver.OnGlobalLayoutListener {
private val isAtLeastSdkR = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
class AssistPopupWindow(
context: Context,
private val parentView: View
) : PopupWindow(context) {
private val isAtLeastSdkR = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
init {
if (!isAtLeastSdkR) {
contentView = Space(context)
softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
width = 0
height = WindowManager.LayoutParams.MATCH_PARENT
}
}
fun start() {
if (!isAtLeastSdkR) {
if (!isShowing && parentView.windowToken != null) {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0)
}
}
}
fun getPopHeight(): Int {
return if (isAtLeastSdkR) 0 else contentView.height
}
}
var observer: ((Int, Int) -> Unit)? = null
private val assistPopupWindow by lazy(LazyThreadSafetyMode.NONE) {
AssistPopupWindow(context, parentView)
}
private var lastKeyboardHeight = 0
private var currentKeyboardHeight = 0
init {
if (!isAtLeastSdkR) {
contentView = Space(context).also {
it.viewTreeObserver.addOnGlobalLayoutListener(this)
}
softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE or
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
inputMethodMode = INPUT_METHOD_NEEDED
width = 0
height = WindowManager.LayoutParams.MATCH_PARENT
}
}
override fun onGlobalLayout() {
if (!isAtLeastSdkR) {
handleOnGlobalLayout()
}
}
fun isShowKeyboard() = currentKeyboardHeight > 120
fun lastIsShowKeyboard() = lastKeyboardHeight > 120
@SuppressLint("NewApi")
fun start() {
if (isAtLeastSdkR) {
(context as Activity).window.decorView.setOnApplyWindowInsetsListener { _, insets ->
insets.getInsets(WindowInsets.Type.navigationBars()).bottom.run {
handlerDispatchEvent(insets.getInsets(WindowInsets.Type.ime()).bottom.minus(this))
insets.inset(0, 0, 0, this)
}
}
} else {
if (!isShowing && parentView.windowToken != null) {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0)
assistPopupWindow.start()
}
}
}
@SuppressLint("NewApi")
fun close() {
observer = null
if (isAtLeastSdkR) {
(context as Activity).window.decorView.setOnApplyWindowInsetsListener(null)
} else {
contentView.viewTreeObserver.removeOnGlobalLayoutListener(this)
dismiss()
assistPopupWindow.dismiss()
}
}
private fun handleOnGlobalLayout() {
val contentHeight = contentView.height
if (contentHeight <= 0) {
return // 忽略无需处理
}
val offset = assistPopupWindow.getPopHeight().minus(contentHeight)
val open = offset > context.dip(100f)
val newHeight = if (open) {
offset
} else {
0
}
handlerDispatchEvent(newHeight)
}
private fun handlerDispatchEvent(height: Int) {
val newHeight = height.coerceAtLeast(0)
if (currentKeyboardHeight == newHeight) {
return
}
lastKeyboardHeight = currentKeyboardHeight
val orientation = context.resources.configuration.orientation
if (newHeight < 120) {
currentKeyboardHeight = 0
notifyKeyboardHeightChanged(0, orientation)
} else {
currentKeyboardHeight = newHeight
notifyKeyboardHeightChanged(newHeight, orientation)
}
}
private fun notifyKeyboardHeightChanged(height: Int, orientation: Int) {
observer?.invoke(height, orientation)
}
}
@Kuki93 大佬,看到你的微信切换表情面板,又看到你这个,方案没有特别大的问题,就是有些手机无法监听,同事的俩台手机就不行,型号华为Mate40系统鸿蒙2.0.0/型号红米Note9pro系统Android11
这个兼容性问题最后有解吗?
使用PopupWindow辅助监听来将主视图设为adjustNothing,确实是个好方法。 onGlobalLayout 的判断经过我使用多种真机测试,发现需要做很多无效性判定。不然很容易产生误判。
1.横屏模式在切入后台,再切回前台,部分手机会产生视图旋转。触发布局调整。 2.底部导航栏状态变更会触发布局调整。 3.有些时候我们并不会把app设置为全屏,计算键盘高度并不总等于物理高减可视底。 4.有些机型点开软键盘后会频繁触发onGlobalLayout。
这个是我自己使用的一个,可以参考一下。 https://bitbucket.org/mm_longcheng/mm-core/src/dev/nwsi/proj/android/src/org/mm/nwsi/mmUIViewLayoutListener.java