| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- package com.hzliuzhi.applet.container
- import android.graphics.Rect
- import android.os.Bundle
- import android.view.View
- import android.view.ViewGroup
- import android.view.ViewTreeObserver
- import android.widget.FrameLayout
- import androidx.activity.ComponentActivity
- import androidx.activity.enableEdgeToEdge
- open class AndroidActivity : ComponentActivity() {
- /**
- * 软键盘适配工具
- */
- private var workaround: AndroidBug5497Workaround? = null
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContent() // 设置内容视图,可被子类重写
- // 初始化软键盘适配工具
- val content = findViewById<ViewGroup?>(android.R.id.content)
- val child = content?.getChildAt(0)
- workaround = if (child != null) AndroidBug5497Workaround(child) else null
- }
- /**
- * 生命周期回调,注册软键盘适配监听。
- */
- override fun onResume() {
- super.onResume()
- workaround?.register()
- }
- /**
- * 生命周期回调,移除软键盘适配监听。
- */
- override fun onPause() {
- super.onPause()
- workaround?.unregister()
- }
- /**
- * 设置内容视图,默认启用EdgeToEdge,可被子类重写。
- */
- open fun setContent() {
- enableEdgeToEdge()
- }
- }
- /**
- * 软键盘适配工具类,处理软键盘弹出时的布局自适应。
- * 通过监听全局布局变化,动态调整根视图高度,防止内容被软键盘遮挡。
- * 参考:https://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible
- * @property rootView 根视图
- */
- private class AndroidBug5497Workaround(private val rootView: View) {
- /** 根视图的布局参数 */
- private val rootViewLayout: FrameLayout.LayoutParams = rootView.layoutParams as FrameLayout.LayoutParams
- /** 用于监听布局变化的 ViewTreeObserver */
- private var viewTreeObserver: ViewTreeObserver = rootView.viewTreeObserver
- /** 用于记录窗口内容区域的 Rect */
- private val contentAreaOfWindowBounds = Rect()
- /** 上一次可用高度 */
- private var usableHeightPrevious = 0
- /**
- * 全局布局监听器,触发内容区域高度调整。
- */
- private val listener = ViewTreeObserver.OnGlobalLayoutListener { possiblyResizeChildOfContent() }
- /**
- * 注册全局布局监听器。
- */
- fun register() {
- if (!viewTreeObserver.isAlive) viewTreeObserver = rootView.viewTreeObserver
- viewTreeObserver.addOnGlobalLayoutListener(listener)
- }
- /**
- * 移除全局布局监听器,避免内存泄漏。
- */
- fun unregister() {
- if (!viewTreeObserver.isAlive) viewTreeObserver = rootView.viewTreeObserver
- viewTreeObserver.removeOnGlobalLayoutListener(listener)
- }
- /**
- * 判断并调整内容区域高度,适配软键盘弹出等场景。
- * 若可用高度发生变化,则重新设置根视图高度并请求布局。
- */
- private fun possiblyResizeChildOfContent() {
- (rootView.parent as? ViewGroup)?.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
- val usableHeightNow = contentAreaOfWindowBounds.height() + contentAreaOfWindowBounds.top
- if (usableHeightNow != usableHeightPrevious) {
- rootViewLayout.height = usableHeightNow
- rootView.layout(
- contentAreaOfWindowBounds.left,
- contentAreaOfWindowBounds.top,
- contentAreaOfWindowBounds.right,
- contentAreaOfWindowBounds.bottom
- )
- rootView.requestLayout()
- usableHeightPrevious = usableHeightNow
- }
- }
- }
|