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

如何实现Android中Bottom Sheet Dialog与键盘的同步联动?

Bottom Sheet Dialog与键盘同步联动解决方案

在Android Kotlin开发中,通过Navigation组件启动Bottom Sheet Dialog Fragment时,会出现Bottom Sheet先向上移动、键盘延迟弹出的不同步问题。已配置adjustResize、设置BottomSheetBehavior为STATE_EXPANDED,尝试过WindowInsetsAnimationCompat Callback但未生效。以下是具体解决方法:


核心解决思路

让Bottom Sheet的展开动画与键盘弹出动画的触发时机对齐,同时利用系统Insets监听联动调整Bottom Sheet位置,确保二者动画同步。


具体修改步骤

1. 调整焦点请求时机,避免动画冲突

不在onStart中直接请求输入框焦点,而是监听BottomSheetBehavior的状态变化,当Bottom Sheet完全展开后再触发焦点请求,让两个动画的启动时机一致。

2. 配置WindowInsetsController,同步Insets变化

通过WindowInsetsController监听键盘显示/隐藏事件,联动调整BottomSheetBehavior的状态,实现动画同步。

3. 优化Dialog窗口配置

调整Dialog的SoftInputMode,确保系统正确处理键盘与Bottom Sheet的布局联动。


修改后的BottomSheetDialogFragment代码

import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.WindowInsetsController
import com.example.keyboardevent.R
import com.example.keyboardevent.databinding.FragmentBottomSheetDialogBinding
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment

class BottomSheetDialogFragment : BottomSheetDialogFragment() {

    private var _binding: FragmentBottomSheetDialogBinding? = null
    private val binding get() = _binding!!
    private var bottomSheetBehavior: BottomSheetBehavior<View>? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStyle(STYLE_NORMAL, R.style.AppBottomSheetDialogTheme)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentBottomSheetDialogBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 获取BottomSheetBehavior实例
        val bottomSheet = (dialog as BottomSheetDialog).findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
        bottomSheet?.let {
            bottomSheetBehavior = BottomSheetBehavior.from(it)
            // 监听BottomSheet状态变化
            bottomSheetBehavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
                override fun onStateChanged(bottomSheet: View, newState: Int) {
                    if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                        // 完全展开后请求焦点,触发键盘弹出
                        binding.input.requestFocus()
                        // 主动显示键盘
                        requireContext().getSystemService(WindowInsetsController::class.java)
                            ?.show(android.view.WindowInsets.Type.ime())
                    }
                }

                override fun onSlide(bottomSheet: View, slideOffset: Float) {}
            })
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val bottomSheetDialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
        bottomSheetDialog.window?.apply {
            // 设置SoftInputMode,确保布局调整与动画同步
            setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE or WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
            // 配置窗口进出动画,与键盘动画节奏匹配
            attributes.windowAnimations = R.style.AppBottomSheetDialogAnimation
        }
        bottomSheetDialog.behavior.apply {
            skipCollapsed = true
            state = BottomSheetBehavior.STATE_EXPANDED
        }
        return bottomSheetDialog
    }

    override fun onDestroyView() {
        super.onDestroyView()
        bottomSheetBehavior?.removeBottomSheetCallback()
        _binding = null
    }
}

可选:添加窗口动画样式

在styles.xml中添加动画样式,让Bottom Sheet的动画节奏与键盘更匹配:

<style name="AppBottomSheetDialogAnimation">
    <item name="android:windowEnterAnimation">@anim/slide_up</item>
    <item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

创建res/anim/slide_up.xml:

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromYDelta="100%"
    android:toYDelta="0%" />

创建res/anim/slide_down.xml:

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromYDelta="0%"
    android:toYDelta="100%" />

其他注意事项

  • 保持Activity的windowSoftInputMode为adjustResize
  • 移除样式中重复的android:windowSoftInputMode配置,避免冲突
  • 若仍存在轻微延迟,可尝试给焦点请求添加短延迟:view.postDelayed({ binding.input.requestFocus() }, 100)

内容的提问来源于stack exchange,提问作者Baia Asanidze

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:02:04