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
相关产品推荐
相关产品推荐

