You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Jetpack Compose:rememberSystemUiController不响应mutableStateOf求助

问题分析与解决建议

问题根源

你的代码存在两个核心问题:

  1. setViewCompositionStrategy被放在Content()Composable内部,会在每次重组时重复执行,干扰Compose的生命周期管理。
  2. 使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 23:10:33