How to set LineHeight using AnnotatedString in Jetpack Compose - android

I'm working right now with AnnotedStrings to create this Text with two different text styles:
I'm setup this text using a SpanStyle. How do I setup the line height this way? In the SpanStyle is missing this attribute.

You can use the ParagraphStyle to define the lineHeight and the lineHeightStyle.
Something like:
buildAnnotatedString {
withStyle(style = ParagraphStyle(lineHeight = 60.sp)) {
withStyle(style = SpanStyle(color = Color.Blue, fontSize= 60.sp)) {
append("Hello")
}
append("Compose")
}
}

Related

Jetpack Compose Text size dp in Huge font

I want to set text size as "DP". so I add extension fuction like below
#Composable
fun Dp.toTextDp(): TextUnit = textSp(density = LocalDensity.current)
private fun Dp.textSp(density: Density): TextUnit = with(density) {
this#textSp.toSp()
}
However I found text line hight issue when change device font size to Huge
Here is my text test code.
there are two text view has different way to set font size
first is using TextStyle
second is just set font Size.
#Composable
fun TextLineLayout(description: String) {
Text(
modifier = Modifier,
text = description,
color = Color.Gray,
style = TextStyle(fontSize = 20.dp.toTextDp())
)
Text(
modifier = Modifier,
text = description,
color = Color.Blue,
fontSize = 20.dp.toTextDp(),
)
}
and then add preview function with fontScale is 2f
#Preview(name = "font_size", fontScale = 2f)
#Composable
fun TextLinePreview() {
MaterialTheme {
TextLineLayoutTest()
}
}
The Hight of Second Text is not my expected.
The reason I wasn't getting the results I was expecting is, I think, is the line height.
At that time, Default lineHeight is lineHeight=24.0.sp
But First TextView has lineHeight=Unspecified because, I think, TextStyle was overrided
Is my analysis correct?
So should I set everty text size with TextStyle if I want to set "DP" size?

Unexpected Text colour alpha in Jetpack Compose Material Theme

I discovered today that MaterialTheme applies an alpha to Text's colour. As you can see from the example attached, when I change the background colour, the text's colour appears to be different because it has a transparency value. I can force set a colour (Text(color = MaterialTheme.colors.onBackground, ....)) and this works correctly but I don't want to have to do this for every single Text.
Why does MaterialTheme do this? How do I override this behaviour?
Compose and Material Compose Material version: 1.2.1
#Preview
#Composable
private fun Preview_Playground() {
MaterialTheme {
Box(Modifier.background(Color.Green)) {
Text("Test", fontWeight = FontWeight.ExtraBold, modifier = Modifier.alpha(1f))
}
}
}
With M2 (androidx.compose.material) the color of the Text is defined by the color parameter or applying a TextStyle.
The default value is Color.Unspecified.
If color = Color.Unspecified and style has no color set, this will be LocalContentColor mixed with LocalContentAlpha.current.
In the Text.kt you can find:
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
}
}
With M3 (androidx.compose.material3) it doesn't happen since LocalContentColor.current is not mixed:
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current
}
}
If you have to use M2, you can define a custom composable for your Text, or you can change the LocalContentAlpha in the theme for the whole application (not only the Text):
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes
){
CompositionLocalProvider(LocalContentAlpha provides 0.5f) {
content()
}
}

Surface content colour slightly different to expected

My Text colour is not the same as that defined in the theme despite it being inside Surface; it appears almost the same but not quite.
This simplistic sample layout is bare bones:
MyTheme {
Surface {
Column(Modifier.padding(12.dp)) {
Text(
text = "This is a line of text, uses surface",
)
Text(
text = "This is a line of text, forced white",
color = Color.White,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
My theme is simple:
#Composable
fun MyTheme(
content: #Composable () -> Unit,
) {
MaterialTheme(
colors = DarkColours,
...,
content = content
)
}
internal val DarkColours = darkColors(
surface = Color(0xFF043143),
onSurface = Color.White,
... // None of the other colours are close to off-white
)
Even if I explicitly specify the colours to use in the surface, the top Text is still off-white (no change):
Surface(
color = Color(0xFF043143),
contentColor = Color.White
) { ... }
Elevation is 0.0dp and uses DefaultElevationOverlay so shouldn't have any effect on contentColor
LocalContentColor.current reports Color(1.0, 1.0, 1.0) when printed by the first Text.
Figured it out while typing this question up so figured I'd share it.
LocalContentAlpha was set to 0.87 inside the contents of MaterialTheme. This is because of its line
LocalContentAlpha provides ContentAlpha.high,
which ultimately resolves to this due to the fact that I'm using a material Color scheme with isLight = false (thanks to darkColors).
private object LowContrastContentAlpha {
const val high: Float = 0.87f
const val medium: Float = 0.60f
const val disabled: Float = 0.38f
}
A workaround is to re-set alpha back to 1.0:
MaterialTheme(
colors = DarkColours,
...
) {
CompositionLocalProvider(
// Undo our "dark" colours triggering Material theme
// to use a low contrast alpha (87%).
LocalContentAlpha provides 1.0f,
content = content
)
}
(or just use lightColors / set isLight = true if you can afford to do this)
This kind of blows my mind, that Material would just change the alpha of literally all of my app's content - I can't find any doc on why it does this either in the material spec!
It happens only with M2 and it doesn't depends on the Surface, but on the Text itself.
The color in the Text is defined by the color parameter or applying a TextStyle. The default value is Color.Unspecified.
If color = Color.Unspecified and style has no color set, this will be LocalContentColor mixed with LocalContentAlpha.current.
In the Text.kt you can find:
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
}
}
As you described in your answer in the MaterialTheme is defined:
fun MaterialTheme( /* .. */ ) {
//...
CompositionLocalProvider(
LocalContentAlpha provides ContentAlpha.high, //0.87f
//...
)
In M3 (androidx.compose.material3) it doesn't happen since LocalContentColor.current is not mixed:
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current
}
}

How adding ImageSpan in jetpack compose Text

As we know, AnnotatedString in JetpackCompose has provided some API of Android's SpannedString.
but I didn't find any way/workaround to inline ImageSpan to a Text (except using AndroidView)
Putting images inside text can be done using AnnotatedString and inlineContent parameter of Text Composable.
Inside buildAnnotatedString { ... } we need to define some id for our inline content using appendInlineContent(id = ...)
Then in Text Composable in inlineContent parameter we provide a map matching this id to InlineTextContent() object.
You can basically put any content there as long as you can define its size up-front in Placeholder.
Here is how it looks with an Image put in the middle of the text:
val annotatedString = buildAnnotatedString {
append("This is text ")
appendInlineContent(id = "imageId")
append(" with a call icon")
}
val inlineContentMap = mapOf(
"imageId" to InlineTextContent(
Placeholder(20.sp, 20.sp, PlaceholderVerticalAlign.TextCenter)
) {
Image(
imageVector = Icons.Default.Call,
modifier = Modifier.fillMaxSize(),
contentDescription = ""
)
}
)
Text(annotatedString, inlineContent = inlineContentMap)

Default Style Jetpack Compose

Does somebody know how to change default style to button?
Style in xml:
<item name="materialButtonStyle">#style/ButtonStyle</item>
And I want to convert it to Jetpack Compose.
In default compose sample(Android Studio Canary) You can see ui.theme folder and it's a analog of values folder but without Strings and Dimens. So how I can add Strings and Dimens to this compose folder?
As described in the nglauber answer you can customize the shape, typography and color in your theme, or in the Button parameters.
Also you can override these values and build a default button style.
Something like:
#Composable
fun DefaultButtonStyle(content: #Composable () -> Unit) {
MaterialTheme(
//override the shape
shapes = MaterialTheme.shapes.copy(small = CutCornerShape(12.dp)),
//Override the typography.button using the merge method
typography = MaterialTheme.typography.copy(
button = MaterialTheme.typography.button.merge(TextStyle(fontSize = 20.sp))),
//override the colors define in the material theme
colors = MaterialTheme.colors.copy(
primary = Color.Yellow,
onPrimary = Color.Blue)
) {
content()
}
}
Then just use it with:
DefaultButtonStyle() {
Button(onClick = { /*....*/ }) {
Text(text = "BUTTON")
}
}
If you look into the Button source, you'll notice that it uses a couple of default values that you can customize (via params or via custom style).
shape: Uses MaterialTheme.shapes.small (you can customized this field in your style);
val shapes = Shapes(
small = CutCornerShape(4.dp), // << here
medium = RoundedCornerShape(4.dp),
large = RoundedCornerShape(0.dp)
)
colors: which is an instance of ButtonColors that provides backgroundColor, contentColor, disabledBackgroundColor and disabledContentColor. Look into the Button.buttonColors function to see how to customize the colors for your button.
In terms of text, the Button component gets the text style from MaterialTheme.typography.button, so you can override this field in your style to customize your button's text.
val typography = Typography(
...
button = defaultTypography.button.copy(
fontFamily = yourFontFamily,
color = Color.Yellow
)
)
For text and dimensions you can continue using XML files (res/values) and refer to them using stringResource(id) and dimensionResource(id) functions respectively.

Categories

Resources