I have an existing TextView with minEms set to 2
I want to convert the TextView to a Compose Text component
Is there an equivalent for minEms in Compose?
I share you this code, I hope it help you.
fontSize = 10.em is the Key.
Text(
text = "How to use em",
style = TextStyle.Default.copy(fontSize = 10.em)
)
Related
I have a text component that height is 48dp and want to set the text center in vertical.
Like the TextView with 48dp height and gravity is center_vertical.
Or I have to put it(Text compose) in Surface component?
Yes, that is correct, you would need to put it in a box for instance, or a column, and center it that way.
Box(modifier = Modifier.fillMaxSize, contentAlignment = Alignment.Center){
Text(text = "My Text") }
This seems to exist in most UI frameworks, in a way that will work with both light and dark themes, but it seems to be absent here.
Currently I've resorted to doing:
val Muted = Color.LightGray
and importing that elsewhere, but it looks bad on light themes.
Any ideas?
Compose has ContentAlpha.medium, that is used, as the name suggests, to display a color as muted.
I don't know if this is the most efficient way to do it, but I usually use it like this:
Text(
text = myText,
color = when {
isEnabled -> MaterialTheme.colors.myColor
else -> MaterialTheme.colors.myColor.copy(alpha = ContentAlpha.medium)
}
)
You could abstract it into a extension field and add it to your themes file:
val Color.muted get() = this.copy(alpha = ContentAlpha.medium)
And use it like this:
color = when {
isEnabled -> MaterialTheme.colors.myColor
else -> MaterialTheme.colors.myColor.muted
Using Color.luminance() value of the background color and choose the Grayscale color of the text in case of dynamic theming.
Using isSystemInDarkTheme() to pick color in combination with contentColorFor(), when we have fixed theming system,
Column(
Modifier.padding(top = 300.dp).pointerHoverIcon(PointerIconDefaults.Text)) {
SelectionContainer {
Column {
Text("Selectable text")
Text(
modifier = Modifier.pointerHoverIcon(PointerIconDefaults.Hand, true),
text = "Selectable text with hand"
)
}
}
Text("Just text with global pointerIcon")
}
PointerIconDefaults.Text:
PointerIconDefaults.Hand:
I don't see any difference between PointerIconDefaults.Hand and PointerIconDefaults.Text
Not sure what you expect from using this modifier since your image shows a floating toolbar. If you need to change how floating toolbar looks like, check out this answer. If you need to change the selection color, check out this one.
Modifier.pointerHoverIcon change the appearance of the mouse pointer over the item. To see this, for example you can connect a BLE mouse to your Android device, not sure if this can be checked in the Emulator.
Any Text has PointerIconDefaults.Text by default.
In jetpack Compose, you can Justify a Text like this:
Text(
text = text,
textAlign = TextAlign.Justify
)
If you want support RTL, you achive this by:
Text(
text = text,
textAlign = TextAlign.Right
)
How can a Text() support RTL text and justify it same time in Jetpack Compose?
After several hour testing, I reach this:
#Composable
fun JustifiedRTLText(
text: String,
modifier: Modifier = Modifier
) {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
Text(
text = text,
textAlign = TextAlign.Justify,
modifier = modifier,
)
}
}
In Jetpack Compose RTL or LTR will automatically set by according to the text content. But we can force it by changing the textDirection of style to TextDirection.Content or TextDirection.RTL
Text(
text = text,
textAlign = TextAlign.Justify,
style = TextStyle(textDirection = TextDirection.Content)
)
This code creates a ClickableText element in Jetpack Compose Composable:
ClickableText(
text = forgotPasswordAnnotatedString,
onClick = {
context.startActivity(intent)
},
modifier = Modifier
.padding(top = mediumPadding)
)
The annotated string is defined here to make the text look like a link:
val forgotPasswordAnnotatedString = buildAnnotatedString {
append(stringResource(R.string.forgot_password))
addStyle(
style = SpanStyle(
textDecoration = TextDecoration.Underline,
color = Color.White,
fontSize = 16.sp,
fontWeight = FontWeight.Medium
),
start = 0,
end = 21,
)
}
When I encounter this text using the TalkBalk screen reader in Android, the screenreader does not make it clear that this is clickable text that will do something which tapped on. The reader just reads the text.
Is there a way to make it clear to the screen reader that this text is interactive? Otherwise should I just use a button and style it to look like a link?
It looks like your intention is for the whole text to be clickable? In which you best option is probably a TextButton as suggested by
Gabriele Mariotti.
But if you wan't only part of the link to be clickable, or to have multiple clickable sections, the best I've been able to land on is to draw an invisible box overtop of the Text. It means that I can control the touch target of the clickable area to be at least 48.dp and can use the semantics{} modifier to control how a screen reader interprets it.
Would welcome any suggestions.
// remember variables to hold the start and end position of the clickable text
val startX = remember { mutableStateOf(0f) }
val endX = remember { mutableStateOf(0f) }
// convert to Dp and work out width of button
val buttonPaddingX = with(LocalDensity.current) { startX.value.toDp() }
val buttonWidth = with(LocalDensity.current) { (endX.value - startX.value).toDp() }
Text(
text = forgotPasswordAnnotatedString,
onTextLayout = {
startX.value = it.getBoundingBox(0).left // where 0 is the start index of the range you want to be clickable
endX.value = it.getBoundingBox(21 - 1).right // where 21 is the end index of the range you want to be clickable
}
)
Note that buttonPaddingX is relative to the Text position not the Window, so you may have to surround both in a Box{} or use ConstraintLayout.
Then to draw the invisible box
Box(modifier = Modifier
.sizeIn(minWidth = 48.dp, minHeight = 48.dp) // minimum touch target size
.padding(start = buttonPaddingX)
.width(buttonWidth)
// .background(Color.Magenta.copy(alpha = 0.5f)) // uncomment this to debug where the box is drawn
.clickable(onClick = { context.startActivity(intent) })
.semantics {
// tell TalkBack whatever you need to here
role = Role.Button
contentDescription = "Insert button description here"
}
)
In my code I'm using pushStringAnnotation(TAG, annotation) rather than reference string indexes directly. That way I can get the start and end index of the clickable area with annotatedString.getStringAnnotations(TAG,0,annotatedString.length).first(). Useful if there a multiple links within the text.
It's disappointing that ClickableText doesn't have accessibility in mind from the get go, hopefully we'll be able to use it again in a future update.
Adding .semantics.contentDescription to the Modifier changes what is read by the screen reader. I had to word contentDescription to make it clear that this was a link to reset the your password.
The screen reader still doesn't recognize the element a clickable but hopefully the description will be useful to convey to the user that this element is interactive.
ClickableText(
text = forgotPasswordAnnotatedString,
onClick = {
context.startActivity(intent)
},
modifier = Modifier
.padding(top = mediumPadding)
// new code here:
.semantics {
contentDescription = "Forgot your password? link"
}
)