Android Bottom Sheet Dialog如何设置scrim显示动画
Bottom Sheet Dialog scrim显示动画实现方案
默认Bottom Sheet Dialog的遮罩层(scrim)没有过渡动画的核心原因是:系统在dialog触发show时直接将window的dim值设置为目标透明度,没有和Bottom Sheet本身的上滑/下滑动画做进度绑定,所以会出现硬弹出的观感。下面是三个经过线上验证的可行实现方案:
方案1:自定义遮罩层绑定BottomSheet滑动回调(兼容性最优)
- 实现成本低,不会有系统API、国产ROM适配问题,是优先推荐的方案
- 具体步骤:
- 初始化Dialog时先关闭系统自带的window遮罩,避免原生硬跳的遮罩层出现:
window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) - 在Dialog的布局根节点下,和Bottom Sheet内容层平级添加一个宽高占满父布局的View作为自定义scrim,初始
alpha=0,背景色设为你需要的半透明黑(通常用#52000000),同时给这个View设置点击事件,触发Dialog取消,和原生scrim交互逻辑对齐。 - 给Dialog绑定的BottomSheetBehavior添加滑动回调,在
onSlide方法里根据当前滑动偏移量动态更新自定义scrim的透明度:addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onSlide(bottomSheet: View, slideOffset: Float) { // slideOffset范围0~1,对应BottomSheet从完全收起至完全展开 binding.scrimView.alpha = slideOffset * 0.32f // 0.32是最终展开时的遮罩透明度,可按需调整 } override fun onStateChanged(bottomSheet: View, newState: Int) {} }) - 动画时长不需要手动设置,因为透明度是跟着BottomSheet本身的滑动动画实时更新的,节奏完全和底部面板对齐,不会出现动画不同步的问题。
- 初始化Dialog时先关闭系统自带的window遮罩,避免原生硬跳的遮罩层出现:
方案2:动态更新window dim值(无额外布局侵入)
- 不需要新增自定义View,适合改动范围受限的场景
- 具体步骤:
- 保留系统的
FLAG_DIM_BEHIND标记,初始化时先将window的dimAmount设为0,避免刚弹出时直接显示全量遮罩。 - 同样在BottomSheetBehavior的
onSlide回调里,根据滑动偏移量实时更新window的dim值:override fun onSlide(bottomSheet: View, slideOffset: Float) { val params = window?.attributes ?: return params.dimAmount = slideOffset * 0.32f window?.attributes = params }
- 保留系统的
- 注意:部分定制ROM对window属性更新做了帧级优化限制,快速滑动时可能出现遮罩更新掉帧的问题,上线前需要做好主流机型适配测试。
方案3:接入Transition框架做整体动效
- 如果项目本身已经使用AndroidX Transition做页面转场,可以直接把scrim动画纳入整体转场逻辑
- 核心配置:将scrim的淡入淡出动画和Bottom Sheet的上滑动画加入同一个TransitionSet,统一设置动画时长和插值器,同时需要给Dialog的window设置
android:windowIsTranslucent=true,避免动画被window背景截断。
内容的提问来源于stack exchange,提问作者Fever
相关产品推荐
相关产品推荐

