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

Compose应用本地化切换Layout Direction时出现闪烁回退问题

Compose应用本地化布局方向切换异常问题

问题现象

  • 应用以"ar"启动时,布局正确设置为RTL;
  • 切换至"en"并重建Activity后,布局先切换为LTR,随后快速闪回RTL;
  • 应用以"en"启动时,布局正确设置为LTR;
  • 切换至"ar"并重建Activity后,布局先切换为RTL,随后快速闪回LTR;
  • 总结:应用始终会回退至初始启动时的布局方向,无论初始是RTL还是LTR。

另外观察到:切换至非初始语言时,MyAppTheme会重组两次,第一次正确设置布局,第二次回退至初始状态。

相关代码

[1] AuthenticationActivity

class AuthenticationActivity : BaseActivity() {
    private lateinit var navController: NavHostController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            navController = rememberNavController()

            MyAppTheme {
                NavHost(navController = navController, startDestination = Graph.AUTH) {
                    authNavGraph(navController)
                }
            }
        }
    }
}

[2] BaseActivity

open class BaseActivity : ComponentActivity() {
    override fun attachBaseContext(baseContext: Context) {
        val initialLocale = Locale(prefs.getValue(Preference.LANGUAGE_KEY, "ar"))

        super.attachBaseContext(AppContextWrapper.wrap(baseContext, initialLocale))
    }
}

[3] authNavGraph

fun NavGraphBuilder.authNavGraph(
    navController: NavHostController,
) {
    navigation(
        route = Graph.AUTH,
        startDestination = AuthScreens.LanguageSelect.route
    ) {
        composable(route = AuthScreens.LanguageSelect.route) {
            LanguageSelectScreen(navController)
        }
        composable(route = AuthScreens.Login.route) {
            LoginScreen(navController)
        }
    }
}

[4] AppContextWrapper

class AppContextWrapper(base: Context?) : ContextWrapper(base) {

    companion object {
        fun wrap(context: Context, newLocale: Locale?): AppContextWrapper {
            val res = context.resources
            val configuration = res.configuration

            return if (BuildUtils.isAtLeast24Api()) {
                configuration.setLocale(newLocale)
                configuration.setLayoutDirection(newLocale)

                val localeList = LocaleList(newLocale)
                LocaleList.setDefault(localeList)
                configuration.setLocales(localeList)

                AppContextWrapper(context.createConfigurationContext(configuration))

            } else if (BuildUtils.isAtLeast17Api()) {
                configuration.setLocale(newLocale)
                configuration.setLayoutDirection(newLocale)

                AppContextWrapper(context.createConfigurationContext(configuration))

            } else {
                configuration.locale = newLocale
                configuration.setLayoutDirection(newLocale)
                res.updateConfiguration(configuration, res.displayMetrics)

                AppContextWrapper(context)
            }
        }
    }
}

[5] LanguageSelectScreen

@Composable
fun LanguageSelectScreen(
    navController: NavController,
    prefs: ILocalPreferencesStorage = get()
) {
    val context = LocalContext.current

        Column(
            Modifier
                .fillMaxSize()
                .padding(horizontal = 16.dp, vertical = 45.dp),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {

val initialLangCode = prefs.getValue(Preference.LANGUAGE_KEY, "ar")

        val (selectedOption, onOptionSelected) = remember {
            mutableStateOf(LocalizationHelper.lang(initialLangCode))
        }

            // Radio Buttons to switch between languages
            Spacer(Modifier.height(40.dp))
            LocalizationHelper.langOptions.forEach { text ->
                Column {
                    Spacer(modifier = Modifier.height(15.dp))
                    RadioButtonStroke(text, selectedOption, onOptionSelected)
                }
            }

            Spacer(Modifier.weight(1f))
            MainRoundedButton(text = stringResource(R.string.save)) {
                val code = LocalizationHelper.code(selectedOption)
                prefs.putValue(Preference.LANGUAGE_KEY, code)

                // Recreate Activity
                context.findActivity()?.recreate()
            }
        }
}

期望解决目标

  • 布局方向切换正常,无回退闪烁现象;
  • 切换语言时MyAppTheme不会发生两次重组。

内容的提问来源于stack exchange,提问作者Mohamed Abu Zaid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 07:57:23