为何给BottomSheetDialogFragment设置样式后,键盘平滑动画消失?
BottomSheetDialogFragment设置样式后丢失平滑键盘动画的问题与解决
问题背景
我实现了一个带有平滑键盘动画的BottomSheetDialogFragment,重要说明:为实现该平滑动画,应用主题使用了Theme.MaterialComponents.DayNight.DarkActionBar。
带有平滑键盘动画的实现代码
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 com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.yocto.wetodo.databinding.TodoInputDialogFragmentBinding class TodoInputDialogFragment : BottomSheetDialogFragment() { private var _binding: TodoInputDialogFragmentBinding? = null // 该属性仅在onCreateView和onDestroyView之间有效 private val binding get() = _binding!! override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = TodoInputDialogFragmentBinding.inflate(inflater, container, false) val root: View = binding.root return root } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) dialog.window?.also { it.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) } return dialog } override fun onDestroyView() { super.onDestroyView() _binding = null } }
平滑键盘动画效果

但当给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 androidx.fragment.app.DialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.yocto.wetodo.R import com.yocto.wetodo.databinding.TodoInputDialogFragmentBinding class TodoInputDialogFragment : BottomSheetDialogFragment() { private var _binding: TodoInputDialogFragmentBinding? = null // 该属性仅在onCreateView和onDestroyView之间有效 private val binding get() = _binding!! override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(DialogFragment.STYLE_NORMAL, R.style.TodoInputDialogFragment) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = TodoInputDialogFragmentBinding.inflate(inflater, container, false) val root: View = binding.root return root } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) dialog.window?.also { it.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) } return dialog } override fun onDestroyView() { super.onDestroyView() _binding = null } }
对应的styles.xml代码
<resources xmlns:tools="http://schemas.android.com/tools"> <style name="TodoInputDialogFragment" parent="Theme.MaterialComponents.Light.BottomSheetDialog"> <item name="android:windowIsFloating">false</item> <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:windowSoftInputMode">adjustResize</item> </style> </resources>
非平滑键盘动画效果

问题原因
动画消失的核心是自定义样式的父主题与原应用主题不兼容:
- 原应用主题
Theme.MaterialComponents.DayNight.DarkActionBar继承自Material的DayNight主题,内置了键盘调整的平滑动画逻辑。 - 自定义样式使用的父主题
Theme.MaterialComponents.Light.BottomSheetDialog,其内部的窗口动画配置覆盖了原主题的平滑过渡行为,导致系统无法触发原本的键盘动画。
解决方法
方案1:修改自定义样式的父主题
将自定义样式的父主题改为与应用主题匹配的DayNight版本,继承自Theme.MaterialComponents.DayNight.BottomSheetDialog:
<resources xmlns:tools="http://schemas.android.com/tools"> <style name="TodoInputDialogFragment" parent="Theme.MaterialComponents.DayNight.BottomSheetDialog"> <item name="android:windowIsFloating">false</item> <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:windowSoftInputMode">adjustResize</item> <!-- 保留其他自定义属性 --> </style> </resources>
方案2:显式指定动画样式
如果需要保留Light主题,可在自定义样式中显式引用原主题的窗口动画样式:
<resources xmlns:tools="http://schemas.android.com/tools"> <style name="TodoInputDialogFragment" parent="Theme.MaterialComponents.Light.BottomSheetDialog"> <item name="android:windowIsFloating">false</item> <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:windowSoftInputMode">adjustResize</item> <item name="android:windowAnimationStyle">@style/Animation.MaterialComponents.DayNight.Dialog</item> </style> </resources>
方案3:代码中兼容主题配置
若不想修改样式,可在onCreateDialog中手动从应用主题获取动画样式并设置:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) dialog.window?.also { it.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) // 从应用主题中获取动画样式 val animStyle = requireContext().theme.obtainStyledAttributes( intArrayOf(android.R.attr.windowAnimationStyle) ).getResourceId(0, 0) it.setWindowAnimations(animStyle) } return dialog }
验证
修改后重新运行,BottomSheetDialogFragment会保留自定义样式的同时,恢复平滑的键盘弹出/收起动画。
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

