Jetpack Composeでダークテーマ設定変更によるステータスバーカラーの切り替え方

Posted by kwmt27 on Sun, Jan 24, 2021

はじめに

Android端末でダークテーマの切り替えをしたとき、Jetpack Composeでステータスバーカラーの切りかえをする方法を調べたので、メモ。

方法

Jetpack Composeのサンプル、Jetsnackのコードを参考にしています。

interface SystemUiController {
    fun setStatusBarColor(
        color: Color,
        darkIcons: Boolean = color.luminance() > 0.5f
    )
}

fun SystemUiController(window: Window): SystemUiController {
    return SystemUiControllerImpl(window)
}

/**
 * An [androidx.compose.runtime.Ambient] holding the current [SysUiController]. Defaults to a
 * no-op controller; consumers should [provide][androidx.compose.runtime.Providers] a real one.
 */
val SysUiController = staticAmbientOf<SystemUiController> {
    FakeSystemUiController
}

private class SystemUiControllerImpl(private val window: Window) : SystemUiController {
    override fun setStatusBarColor(
        color: Color,
        darkIcons: Boolean
    ) {
        window.statusBarColor = color.toArgb()
        @Suppress("DEPRECATION")
        if (darkIcons) {
            window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or
                    View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
        } else {
            window.decorView.systemUiVisibility = window.decorView.systemUiVisibility and
                    View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
        }
    }
}

private object FakeSystemUiController : SystemUiController {
    override fun setStatusBarColor(color: Color, darkIcons: Boolean) = Unit
}

SystemUiControllerを定義し、setStatusBarColorでステータスバーカラーの実装をします。

アプリ全体の設定になるので、AmbientとしてSysUiControllerを定義しておきます。

val SysUiController = staticAmbientOf<SystemUiController>

MainActivityのsetContentで provideし、

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val systemUiController = remember { SystemUiController(window) }
            Providers(SysUiController provides systemUiController) {
                JetpackComposePlayGroundTheme {
                    // 省略
                }
            }
        }
    }
}

JetpackComposePlayGroundTheme内でSysUiController.currentで SystemUiControllerを取り出し、 onCommitでカラーが変わったら sysUiController.setStatusBarColorを呼び出します。

@Composable
fun JetpackComposePlayGroundTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable() () -> Unit
) {
    val colors = if (darkTheme) {
        DarkColorPalette
    } else {
        LightColorPalette
    }
    val sysUiController = SysUiController.current
    onCommit(sysUiController, colors.background) {
        sysUiController.setStatusBarColor(
            color = colors.background// .copy(alpha = 0.95f)
        )
    }
    // 省略
}

下の動画のようになります。

参考



comments powered by Disqus