Android BottomSheet中间状态实现问题:拖拽时出现抖动
解决BottomSheet三状态切换抖动问题
问题描述
需要实现BottomSheet的三状态平滑切换:
- 向上滑动:底部折叠态 → 屏幕中间态 → 顶部展开态
- 向下滑动:顶部展开态 → 屏幕中间态 → 底部折叠态
当前代码在拖拽到中间位置时出现抖动,推测是状态计算逻辑冲突导致循环回调。
问题原因
原代码在onSlide回调中频繁修改peekHeight并强制切换STATE_COLLAPSED/STATE_EXPANDED,导致BottomSheetBehavior内部状态紊乱,触发重复回调引发抖动;同时错误复用了折叠/展开状态,没有利用BottomSheet原生的半展开能力。
解决方案
利用Material Design BottomSheetBehavior原生的**半展开(STATE_HALF_EXPANDED)**状态,通过配置锚点参数实现三状态切换,避免手动修改状态引发冲突:
- 初始化时配置三个核心参数:底部折叠高度、半展开位置比例、允许三状态切换
- 移除
onSlide中的强制状态修改逻辑,让BottomSheet自行处理过渡
修复后的代码
package com.example.test import android.os.Bundle import android.util.TypedValue import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import com.google.android.material.bottomsheet.BottomSheetBehavior class MainActivity : AppCompatActivity() { private lateinit var bottomSheetBehavior: BottomSheetBehavior<ConstraintLayout> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val bottomSheet = findViewById<ConstraintLayout>(R.id.bottomSheet) bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet) // 初始化三状态核心配置 initBottomSheetConfig() bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { // 可在此根据状态变化添加自定义逻辑,比如更新UI when(newState) { BottomSheetBehavior.STATE_COLLAPSED -> {} // 底部折叠态 BottomSheetBehavior.STATE_HALF_EXPANDED -> {} // 屏幕中间态 BottomSheetBehavior.STATE_EXPANDED -> {} // 顶部展开态 else -> {} } } override fun onSlide(bottomSheet: View, slideOffset: Float) { // 移除原强制状态切换逻辑,避免与原生行为冲突 } }) } private fun initBottomSheetConfig() { // 设置底部折叠态高度(32dp) bottomSheetBehavior.peekHeight = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 32f, resources.displayMetrics ).toInt() // 设置半展开态为屏幕垂直中间(占屏幕高度50%) bottomSheetBehavior.halfExpandedRatio = 0.5f // 允许在折叠、半展开、展开三个状态间切换 bottomSheetBehavior.skipCollapsed = false // 禁用内容适配,确保半展开态严格按比例显示 bottomSheetBehavior.isFitToContents = false } }
关键说明
- 依赖原生
STATE_HALF_EXPANDED状态,无需手动计算位置,彻底避免状态循环 halfExpandedRatio控制半展开位置,0.5对应屏幕垂直中线skipCollapsed = false是三状态切换的核心开关,允许BottomSheet在三个状态间平滑过渡- 移除
onSlide中的强制状态修改,让BottomSheetBehavior自行处理拖拽逻辑,消除抖动
内容的提问来源于stack exchange,提问作者Captain Nemo
相关产品推荐
相关产品推荐

