如何实现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
相关产品推荐
相关产品推荐

