How do I reference a resource style from Compose widget?
styles.xml
<style name="Style.Monet.TextView.HeaderSubtext" parent="Widget.AppCompat.TextView">
<item name="android:textColor">#737373</item>
<item name="android:textSize">12sp</item>
<item name="android:layout_marginStart">16dp</item>
<item name="android:layout_marginBottom">16dp</item>
<item name="android:layout_marginEnd">24dp</item>
</style>
MyComponent.kt
Text(text = "June 2021", style = TextStyle(R.style.Style_TextView_HeaderSubtext))
But this doesn't work. Is there a way to make this work?
You can't do that, because Compose Text is styled differently, and TextStyle it not responsible so all xml style is responsible. As an example, you cannot add margins.
You can create compose TextStyle:
val textStyle = TextStyle(
color = Color(0xFF737373),
fontSize = 12.sp,
)
And use it globally in your project or pass to your theme. This is a preferred way to use styles in compose, check out more about it in the theming documentation. Customize one of material available styles:
val typography = Typography(
body1 = TextStyle(
color = Color(0xFF737373),
fontSize = 12.sp,
)
)
Pass it to your theme:
#Composable
fun ComposePlaygroundTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: #Composable () -> Unit
) {
val colors = if (darkTheme) {
DarkThemeColors
} else {
LightThemeColors
}
MaterialTheme(
colors = colors,
typography = typography,
shapes = shapes,
content = content,
)
}
Apply Theme at the composable root:
setContent {
ComposePlaygroundTheme {
// your composables
}
}
After that you can use it like this:
Text("",
style = MaterialTheme.typography.body1,
)
To apply margins in compose you need to use padding modifier. Check out more about layout in compose in the layout documentation:
If you wanna reuse same styled text in compose, you can create your own composable with predefined style and padding:
#Composable
fun ProjectText(text: String, modifier: Modifier) {
// without material theme you can just define text style here and pass to text
// val textStyle = TextStyle(
// color = Color(0xFF737373),
// fontSize = 12.sp,
)
Text("",
style = MaterialTheme.typography.body1,
modifier = modifier
.padding(start = 16.dp, end = 24.dp, bottom = 16.dp)
)
}
Usage:
ProjectText("June 2021")
Related
I have a problem with adding subtitle to the TopAppBar Composable. I am trying to implement LargeTopAppBar from Material Design 3, but with extra subtitle on it. The issue I am currently facing is that it renders twice. Below is my Composable:
#Composable
private fun HomeTopBar(
modifier: Modifier = Modifier,
title: String,
subtitle: String,
navigateToProfileScreen: () -> Unit,
navigateToAboutScreen: () -> Unit
) {
LargeTopAppBar(
modifier = modifier,
title = {
Column {
Text(
text = title,
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onSurface
)
Text(
text = subtitle,
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
},
actions = {
NavigationDropDownMenu(
navigateToProfileScreen = navigateToProfileScreen,
navigateToAboutScreen = navigateToAboutScreen
)
},
)
}
For some reason it renders twice. I think that this problem is related to the fact that this top app bar has 2 modes (pinned and expanded).
Visual preview:
Here is preview of my composable function to highlight the problem:
Dependencies I used in the project:
implementation 'androidx.compose.material3:material3:1.0.0-beta01'
compose_version = '1.3.0-beta01'
You have to remove the color attribute inside the Text elements in the title and subtitle.
Text(
text = title,
style = MaterialTheme.typography.headlineMedium,
//color = MaterialTheme.colorScheme.onSurface
)
Currently you can only define the same color for both Text using the colors attribute in the LargeTopAppBar :
LargeTopAppBar(
colors = TopAppBarDefaults.largeTopAppBarColors(
titleContentColor=MaterialTheme.colorScheme.onSurface
),
//...
)
Finally use only M3 components (androidx.compose.material3.*) in the LargeTopAppBar, not M2 (androidx.compose.material.*) components.
.
Is it possible to adjust the tonalElevation (but not the shadowElevation) of Material Design 3 components?
It looks as though it's only possible to adjust both. Below is the implementation of a Floating Action Button in Material Design 3. The same problem exists with other components.
#Composable
fun FloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = FabPrimaryTokens.ContainerShape,
containerColor: Color = FabPrimaryTokens.ContainerColor.toColor(),
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
content: #Composable () -> Unit,
) {
Surface(
onClick = onClick,
modifier = modifier,
shape = shape,
color = containerColor,
contentColor = contentColor,
tonalElevation = elevation.tonalElevation(interactionSource = interactionSource).value,
shadowElevation = elevation.shadowElevation(interactionSource = interactionSource).value,
interactionSource = interactionSource,
) {
CompositionLocalProvider(LocalContentColor provides contentColor) {
// Adding the text style from [ExtendedFloatingActionButton] to all FAB variations. In
// the majority of cases this will have no impact, because icons are expected, but if a
// developer decides to put some short text to emulate an icon, (like "?") then it will
// have the correct styling.
ProvideTextStyle(
MaterialTheme.typography.fromToken(ExtendedFabPrimaryTokens.LabelTextFont),
) {
Box(
modifier = Modifier
.defaultMinSize(
minWidth = FabPrimaryTokens.ContainerWidth,
minHeight = FabPrimaryTokens.ContainerHeight,
),
contentAlignment = Alignment.Center,
) { content() }
}
}
}
}
There's an extension function on a ColorScheme class, that converts an Elevation into a Color: surfaceColorAtElevation().
TextField(
...
colors = TextFieldDefaults.textFieldColors(
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)
)
)
Also, there are six different Elevation levels in Material 3 (https://m3.material.io/styles/elevation/tokens):
Level 0: 0dp
Level 1: 1dp
Level 2: 3dp
Level 3: 6dp
Level 4: 8dp
Level 5: 12dp
In Type.kt Typography I defined h1 TextStyle like this:
h1 = TextStyle(
fontFamily = FontFamily.SansSerif,
fontWeight = FontWeight.W500,
fontSize = 70.sp,
color = Color(0xFFF8F9FC)
),
Now how can I define the Text widget to be an h1 so these TextStyles applies automatically?
You can get the current theme h1 from any #Composable with MaterialTheme.typography.h1, so your widget might look like this:
#Composable
fun TextH1(
text: String,
modifier: Modifier = Modifier,
) {
Text(
text = text,
modifier = modifier,
style = MaterialTheme.typography.h1,
)
}
If you plan on using your style globally for all text that you want identified as h1, you should create a custom composable for that and apply your style there:
#Composable
fun TextH1(
text: String,
modifier: Modifier = Modifier
) {
Text(text = text, modifier = modifier, textStyle = h1)
}
Alternatively, you could use CompositionLocal, but that tends to become cumbersome if used extensively.
In Jetpack Compose, TopAppBar shows default background color irrespective of what we added to themes.xml.
So how can we change TopAppBar background color from themes.xml so it's applied globally to the App?
TopAppBar(
title = { Text("Activity") },
navigationIcon = {
IconButton(onClick = { onBackPressed() }) {
Icon(Icons.Filled.ArrowBack, contentDescription = null)
}
}
)
themes.xml
<style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">#android:color/black</item>
<item name="colorPrimaryVariant">#android:color/holo_orange_dark</item>
<item name="colorOnPrimary">#android:color/white</item>
</style>
Note : we can change it through backgroundColor attribute of TopAppBar but here I want to achieve it globally.
The accepted answer explains what to do adequately. There is one thing you might need to keep in mind, though.
TopAppBar uses MaterialTheme.colors.primarySurface as the background color, and it's defined as the following.
[androidx/compose/material/Colors.kt]
val Colors.primarySurface: Color get() = if (isLight) primary else surface
In other words, if the device is in the light mode, it uses primary, and in the dark mode, it uses surface.
Suppose I have a theme with everything as default values.
private val DarkColorPalette = darkColors()
private val LightColorPalette = lightColors()
#Composable
fun ComposeTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: #Composable () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
)
lightColors and darkColors have the following values by default.
fun lightColors(
primary: Color = Color(0xFF6200EE),
...
)
fun darkColors(
surface: Color = Color(0xFF121212),
...
)
When the device is in the light mode, primary (0xFF6200EE) will be TopAppBar's background color.
But when the device is in the dark mode, surface (0xFF121212) is not TopAppBar's background color. It's slightly lighter; 0xFF282828 to be exact.
The reason is TopAppBar has a built-in elevation, which is 4.dp by default.
[androidx/compose/material/AppBar.kt]
#Composable
fun TopAppBar(
...
elevation: Dp = AppBarDefaults.TopAppBarElevation // 4.dp
) {
This most likely won't cause a problem, but it might matter if you want to apply the exactly same background color to somewhere else, such as setting the same color for the status area's background.
val systemUiController = rememberSystemUiController()
systemUiController.setSystemBarsColor(color = Color(0xFF282828))
Note that for this particular case, it would be easier if you just go full screen and add padding at the top.
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
MyAppTheme {
Surface(
modifier = Modifier.systemBarsPadding().fillMaxSize(), // <--
) {
...
}
}
}
For the TopAppBar and the other composables the basis of theming is the MaterialTheme composable and not the AppCompat/MaterialComponents XML themes.
The TopAppBar uses the backgroundColor attribute.
The default value is defined by MaterialTheme.colors.primarySurface.
You can change these colors globally defining your theme adding your Colors and passing them to a MaterialTheme:
private val LightColors = lightColors(
primary = Yellow500,
//...
)
Otherwise you can simply use :
TopAppBar(
title = { Text("Activity") },
backgroundColor = /*...*/,
/* ... */
)
If you want to use the AppCompat XML themes in Jetpack Compose you can use the AppCompat Compose Theme Adapter provided by the accompanist library.
When you create a new project in studio, you get a file named Theme.kt, in which there are color palettes named lightColors and darkColors. You should modify the parameters of those values to achieve the result globally in your app.
I am trying to customize the Typography in my project. But it not affected in my widgets.
My TypoGraphy customization:
Code:
subtitle1 = TextStyle(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
)
In my Text :
Text(text = "Homemade veg pizza", style = MaterialTheme.typography.subtitle1)
My Output :
My problem:
Fontsize and fontfamily not changed. It looks same like default text. How to set custom TypoGraphy in Jetpack Compose?
It's my mistake. I figure out.
We need to set the MaterialTheme before use custom TypoGraphy.
In my rootView I place my rootView under the MaterialTheme. Issue fixed.
setContent {
MaterialTheme { //I missed this line
ThemesRootView()
}
}
Output: