2

I'm using Compose in Fragment and here's my fragment code:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    binding.composeView.apply {
        setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
        setContent {
            MyTheme {
                ChooseLanguageScreen()
            }
        }
    }
}

when user choose a new language, I change app's locale and recreate activity using requireActivity().recreate(). after activity got recreated all resources including strings and drawables change and new resources are loaded except font family. I have included fonts for each locale in app resources:

enter image description here

to change fonts I have to restart the application. here's how I provide fonts in the theme:

val fonts = FontFamily(
Font(R.font.myFont, weight = FontWeight.Normal),
Font(R.font.myFont_bold, weight = FontWeight.Bold),
Font(R.font.myFont_medium, weight = FontWeight.Medium),
)


val myTypography = Typography(
body1 = TextStyle(
    fontFamily = font,
    fontWeight = FontWeight.Normal,
    fontSize = 16.sp
),
subtitle2 = TextStyle(
    fontFamily = font,
    fontWeight = FontWeight.Normal
)
)

and here's the theme:

@Composable
fun MyTheme(content: @Composable () -> Unit) {
MaterialTheme(
    colors = lightColorPalette,
    typography = typography,
    shapes = Shapes,
    content
)
}

I guess I have to recompose the theme but I don't know how, any solutions?

2 Answers2

0

Your case is a bit different than mine. But changing Typography in the app Theme is helping to recompose the Theme. Here is a quick example:

#1 Use StateFlow to let Theme know the language is changed:

In a ViewModel:

val _langState = MutableStateFlow(Lang.DEFAULT)
val langState: StateFlow<Lang> = _langState.asStateFlow()

In a Fragment:

  setContent {
            val languageState by viewModel.langState.collectAsStateWithLifecycle()

            AppTheme(language = languageState) {
                MainApp()
            }
        }

#2 Change language state

  _langState.update {
      Lang.DEFAULT
  }

#3 AppTheme will be recomposed every time the language state changed

@Composable
fun AppTheme(
    language: Lang = Lang.DEFAULT,
    content: @Composable () -> Unit
) {
   
    val typography = when(language) {
        Lang.ENG -> TypographyENG
        else -> TypographyDefault
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = typography
    ) {
        content()
    }
}
enum class Lang {
    DEFAULT,
    ENG
}

Hoping it would help a bit.

Dmitri Chernysh
  • 260
  • 1
  • 7
0

Finally, I found a good solution for this issue, Fonts to be defined as follows:

val MyFontFamily: FontFamily
    get() {
        return FontFamily(
            Font(
                if (Locale.getDefault().language == Locale("ar").language) R.font.regular_ar else R.font.regular_en,
                FontWeight.Normal
            ),
            Font(
                if (Locale.getDefault().language == Locale("ar").language) R.font.medium_ar else R.font.medium_en,
                FontWeight.Medium
            ),
            Font(
                if (Locale.getDefault().language == Locale("ar").language) R.font.bold_ar else R.font.bold_en,
                FontWeight.Bold
            ),
        )
    }

And your custom typography to be as follows:

val Typography.Caption1R: TextStyle
    @Composable
    get() {
        return TextStyle(
            fontFamily = MyFontFamily,
            fontWeight = FontWeight.Normal,
            fontSize = 12.sp,
            letterSpacing = 0.sp,
        )
    }

Then usage as follows:

Text(text = "Hello",style = MaterialTheme.typography.CallOutB)
Ibrahim Disouki
  • 2,642
  • 4
  • 21
  • 52