You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android使用Insets适配软键盘时Toolbar被裁剪问题求助

问题:API 30+ 适配软键盘时Toolbar被裁剪

之前在API 30以下,我用以下代码让界面响应屏幕键盘:

requireActivity().window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)

但该方法现已废弃,于是我尝试通过Insets适配,编写了以下代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    requireActivity().window.setDecorFitsSystemWindows(false)
    requireActivity().window.decorView.setOnApplyWindowInsetsListener { v, windowInsets ->
        val imeHeight = windowInsets.getInsets(WindowInsets.Type.ime())
        val statusBarsHeight = windowInsets.getInsets(WindowInsets.Type.statusBars())

        v.setPadding( /*left  */ imeHeight.left,       // = 0
                      /*top   */ statusBarsHeight.top, // = 66
                      /*right */ imeHeight.right,      // = 0
                      /*bottom*/ imeHeight.bottom)     // = 0
        WindowInsets.Builder()
            .setInsets(0, imeHeight)
            .build()
    }
}

现在Toolbar不再上移,但padding把Toolbar部分区域裁剪了(左侧为正常布局,右侧为异常布局):
布局对比图


问题原因与解决方法

核心问题

  1. 错误给DecorView设置padding:直接给整个DecorView设置顶部padding为状态栏高度,会让内部的Toolbar被向下挤压,同时DecorView的padding是向内的,会覆盖Toolbar顶部区域。
  2. Insets返回逻辑错误:自定义的Insets构建方式不符合规范,没有正确传递未处理的Insets,导致子视图无法获取正确的布局参考。

正确实现方式

方式1:直接替代旧API效果(推荐)

如果只是需要实现原SOFT_INPUT_ADJUST_RESIZE的软键盘适配效果,无需手动处理Insets,直接用新API替代:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    requireActivity().window.setSoftInputMode(
        WindowInsetsControllerCompat.BEHAVIOR_RESIZE_WHEN_IMMERSIVE
    )
} else {
    requireActivity().window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
}

方式2:手动处理Insets(适合自定义布局)

如果需要自定义Insets逻辑,不要直接操作DecorView的padding,而是针对具体子视图设置对应Insets:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    requireActivity().window.setDecorFitsSystemWindows(false)
    requireActivity().window.decorView.setOnApplyWindowInsetsListener { v, windowInsets ->
        val imeInsets = windowInsets.getInsets(WindowInsets.Type.ime())
        val statusBarInsets = windowInsets.getInsets(WindowInsets.Type.statusBars())
        
        // 给内部子视图分别设置Insets
        v.children.forEach { child ->
            when (child.id) {
                R.id.toolbar -> {
                    // Toolbar设置顶部padding避开状态栏
                    child.setPadding(child.paddingLeft, statusBarInsets.top, child.paddingRight, child.paddingBottom)
                }
                R.id.content_layout -> {
                    // 内容布局设置底部padding避开软键盘
                    child.setPadding(child.paddingLeft, child.paddingTop, child.paddingRight, imeInsets.bottom)
                }
            }
        }
        
        // 正确返回处理后的Insets,让系统继续传递
        windowInsets.consume(WindowInsets.Type.ime() or WindowInsets.Type.statusBars())
    }
}

补充说明

  • setDecorFitsSystemWindows(false)会关闭系统自动Insets处理,所有布局适配需手动完成。
  • 避免直接修改DecorView的padding,应针对具体功能视图(如Toolbar、内容区)单独设置Insets,防止布局重叠或裁剪。
  • 返回Insets时需调用consume或传递未处理的Insets,确保子视图能获取正确的布局参考。

内容的提问来源于stack exchange,提问作者Tobias Reich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 08:13:20