Android Jetpack Compose:rememberSystemUiController不响应mutableStateOf求助
问题分析与解决建议
问题根源
你的代码存在两个核心问题:
setViewCompositionStrategy被放在Content()Composable内部,会在每次重组时重复执行,干扰Compose的生命周期管理。- 使用
SideEffect响应状态变化会导致不必要的重复执行,且无法保证状态变化时的精准触发。
修正方案(基于Accompanist SystemUiController)
以下是调整后的代码,解决状态更新不触发状态栏变化的问题:
class MyView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AbstractComposeView(context, attrs, defStyleAttr) { private val hide = mutableStateOf(false) var hideBars: Boolean get() = hide.value set(value) { hide.value = value } // 初始化时设置视图重组策略,避免重复执行 init { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow) } @Composable override fun Content() { val systemUiController = rememberSystemUiController() // 仅在hide.value变化时执行状态栏更新 LaunchedEffect(hide.value) { systemUiController.isStatusBarVisible = !hide.value } Launch() } }
关键调整说明
- 将
setViewCompositionStrategy移至init块:该配置属于View生命周期的初始化逻辑,无需在每次Compose重组时重复设置。 - 用
LaunchedEffect替代SideEffect:LaunchedEffect会严格监听传入的hide.value状态,仅当值变化时才执行状态栏更新操作,避免无意义的重复调用。 - 确保依赖正确:使用
rememberSystemUiController需要添加Accompanist库依赖,在build.gradle中引入:implementation "com.google.accompanist:accompanist-systemuicontroller:0.32.0"
替代方案(原生Android API,无第三方依赖)
如果不想依赖Accompanist库,可以直接通过Android原生WindowInsetsController控制状态栏,无需依赖Compose重组逻辑:
class MyView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AbstractComposeView(context, attrs, defStyleAttr) { private val hide = mutableStateOf(false) var hideBars: Boolean get() = hide.value set(value) { hide.value = value // 直接触发状态栏更新,无需等待Compose重组 updateStatusBarVisibility(!value) } init { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow) } private fun updateStatusBarVisibility(visible: Boolean) { val window = (context as? Activity)?.window ?: return val insetsController = window.insetsController ?: return if (visible) { insetsController.show(WindowInsets.Type.statusBars()) window.statusBarColor = ContextCompat.getColor(context, R.color.default_status_bar) } else { insetsController.hide(WindowInsets.Type.statusBars()) window.statusBarColor = Color.TRANSPARENT } } @Composable override fun Content() { Launch() } }
这个方案直接在hideBars的setter中调用原生API更新状态栏,响应更直接,避免了Compose重组可能带来的延迟或冲突。
内容的提问来源于stack exchange,提问作者Gonki
相关产品推荐
相关产品推荐

