Theming và Material Design trong Compose
1. Material 3 Theme
@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context)
else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}2. Color Scheme
private val LightColorScheme = lightColorScheme(
primary = Color(0xFF6200EE),
onPrimary = Color.White,
primaryContainer = Color(0xFFBB86FC),
onPrimaryContainer = Color.Black,
secondary = Color(0xFF03DAC6),
onSecondary = Color.Black,
background = Color(0xFFFFFBFE),
onBackground = Color(0xFF1C1B1F),
surface = Color(0xFFFFFBFE),
onSurface = Color(0xFF1C1B1F),
error = Color(0xFFB00020),
onError = Color.White
)
private val DarkColorScheme = darkColorScheme(
primary = Color(0xFFBB86FC),
onPrimary = Color.Black,
primaryContainer = Color(0xFF6200EE),
secondary = Color(0xFF03DAC6),
background = Color(0xFF1C1B1F),
surface = Color(0xFF1C1B1F)
)3. Sử dụng Theme Colors
@Composable
fun ThemedCard() {
Card(
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant
)
) {
Text(
text = "Themed Text",
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}4. Typography
val Typography = Typography(
displayLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 57.sp,
lineHeight = 64.sp
),
headlineMedium = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 28.sp,
lineHeight = 36.sp
),
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Bold,
fontSize = 22.sp,
lineHeight = 28.sp
),
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp
),
labelMedium = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 12.sp,
lineHeight = 16.sp
)
)Sử dụng Typography
@Composable
fun TypographyExample() {
Column {
Text(
text = "Headline",
style = MaterialTheme.typography.headlineMedium
)
Text(
text = "Body text",
style = MaterialTheme.typography.bodyLarge
)
}
}5. Custom Fonts
val CustomFontFamily = FontFamily(
Font(R.font.roboto_regular),
Font(R.font.roboto_bold, FontWeight.Bold),
Font(R.font.roboto_italic, style = FontStyle.Italic)
)
val CustomTypography = Typography(
bodyLarge = TextStyle(
fontFamily = CustomFontFamily,
fontSize = 16.sp
)
)6. Shapes
val Shapes = Shapes(
extraSmall = RoundedCornerShape(4.dp),
small = RoundedCornerShape(8.dp),
medium = RoundedCornerShape(12.dp),
large = RoundedCornerShape(16.dp),
extraLarge = RoundedCornerShape(24.dp)
)
@Composable
fun ShapedCard() {
Card(
shape = MaterialTheme.shapes.medium
) {
Text("Shaped Card")
}
}7. Dark/Light Mode Toggle
@Composable
fun ThemeToggleScreen() {
var isDark by remember { mutableStateOf(false) }
MyAppTheme(darkTheme = isDark) {
Scaffold {
Switch(
checked = isDark,
onCheckedChange = { isDark = it }
)
}
}
}8. CompositionLocal
// Define
val LocalCustomColors = staticCompositionLocalOf { CustomColors() }
data class CustomColors(
val success: Color = Color.Green,
val warning: Color = Color.Yellow
)
// Provide
@Composable
fun MyAppTheme(content: @Composable () -> Unit) {
CompositionLocalProvider(
LocalCustomColors provides CustomColors()
) {
MaterialTheme(content = content)
}
}
// Use
@Composable
fun SuccessMessage() {
val customColors = LocalCustomColors.current
Text("Success!", color = customColors.success)
}9. Material Components Styling
@Composable
fun StyledButton() {
Button(
onClick = { },
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.tertiary,
contentColor = MaterialTheme.colorScheme.onTertiary
),
shape = MaterialTheme.shapes.large,
elevation = ButtonDefaults.buttonElevation(
defaultElevation = 8.dp
)
) {
Text("Styled Button")
}
}10. Theme trong Preview
@Preview(name = "Light")
@Preview(name = "Dark", uiMode = UI_MODE_NIGHT_YES)
@Composable
fun ThemedPreview() {
MyAppTheme {
Surface {
MyScreen()
}
}
}📝 Tóm tắt
| Component | Mô tả |
|---|---|
| MaterialTheme | Theme container |
| colorScheme | Colors |
| typography | Text styles |
| shapes | Corner shapes |
| dynamicColor | Android 12+ colors |
| CompositionLocal | Custom theme values |
Last updated on