たくさんの自由帳

Jetpack Compose で他の構成の Resources を使いたい

投稿日 : | 0 日前

文字数(だいたい) : 1942

どうもこんばんわ。
Xperia 1 VIIの交換面倒だからって後回しにしてたらついにハガキ来た。
いや、いい加減いかないとまずいと思って、今、交換機の入荷待ちなのよね。メッセージR(←え?!??!!!?)で連絡が来るとかなんとか

数日後にはショートメールも来た。2回目くらい。

sms

本題

ブラウザのシークレットモードってUIがライトテーマでも、シークレット感を出すため?なのか、無理やりダークモードになりますよね。
こーゆーのを実装するの、テーマによらず常にそれ用の色を当てる真面目な方法がありますが、もう一つ、すでにあるダークテーマを無理やり適用する事もできます。

JetpackComposeContext#createConfigurationContextを使いたい。
返り値の、無理やりダークモードにしたResoucesをなんとか適用したい。

無理やりすればcolors.xmlもそれ用になるし、言語を無理やり変えればその言語のstrings.xmlになります。

大昔に書いた記事の JetpackCompose リメイク

これをJetpackComposeでうまく使う方法を思いつきました。ここに書きます。
(というかJetpackComposestringResource()コード眺めたたら見つけた)

環境

Jetpack Compose BOM 2025.08.00が必要です

なまえあたい
Android StudioAndroid Studio Narwhal 3 Feature Drop 2025.1.3
端末Pixel 8 Pro

答え

result

2025.08.00 ?からLocalResourcesってComposition Localができました。
今まではLocalContext.current.resourcesしてアクセスしていましたが、いまは出来た方を使ってるはず?

で、そのLocalResourcesの値をCompositionLocalProvider { }で上書きしちゃえば、Context#createConfigurationContextで出来たResoucesJetpackComposeでも使える!!

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            LocelResourcesDarkTheme {
                MainScreen()
            }
        }
    }
}

@Composable
private fun MainScreen() {
    val context = LocalContext.current
    val configuration = LocalConfiguration.current

    // Resources を作る
    // 多分本来は Context を作るものだが、Context は上書きしたくないので、Resources だけ取得する
    val newResources = context.createConfigurationContext(Configuration(configuration).apply {
        uiMode = Configuration.UI_MODE_NIGHT_YES
    }).resources

    Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->

        Column(
            modifier = Modifier
                .padding(innerPadding)
                .background(Color.Red)
        ) {


            CompositionLocalProvider(LocalResources provides newResources) {
                // colorResource 等は今の LocalResources を参照するので
                Text(
                    text = "Resources 上書き",
                    color = colorResource(R.color.text_color)
                )
            }

            Text(
                text = "Resources もともと",
                color = colorResource(R.color.text_color)
            )

        }
    }
}

違いがわかるようにvalues/colors.xml (ライトテーマ)values-night/colors.xml (ダークテーマ)にそれぞれ別の色を当てます。

<color name="text_color">@android:color/black</color>
<color name="text_color">@android:color/white</color>

colors.xml

よくある質問

LocalContextCompositionLocalProvider { }で上書きすれば、過去バージョでも動くじゃん。

それだと、LocalContext.current as Activity利用できなくなります。
Context#createConfigurationContextで返ってきたContextは、たとえ元々がActivityでも、android.app.ContextImplが返され、もちろんinstanceof Activityfalseを返します。

おわりに

Xperia 1 VIIはやく来てほしいです