I am building a chat screen using Jetpack Compose, Each message draw a column that takes the full width of the screen, and inside the column, I draw a time Text at the center of the screen width, and below the time I draw a message Text that takes between 0 and 0.75 of the screen width. If the message width is bigger than 0.75 of the screen width it takes multiple lines, but I notice that the space at soft line break is very big and ugly, how can I reduce it? I want to achieve the same result in the left image below.
#Composable
fun MessageRow() {
Column {
// here goes time then a surface contains message
Surface(
color = MaterialTheme.colors.background,
modifier = Modifier
.widthIn(0.dp, 265.dp)
) {
Text(
text = "I was distraught to attend the meeting.",
color = Color.Black
)
}
}
}
Related
In my app, there is a button that the height of it needs to be precisely 0.2 times the screen height. For example, if the screen size is 1000 px, then its height should be 200 px. No matter the screen size, its height should always be 0.2 times that of the screen.
However, whatever I have done, I cannot get it to be work the same in different screen sizes.
These are my approaches:
1)Using DP from LocalConfiguration
// Results in very small for Pixel 2 and almost correct in Pixel 6 emulator
// So small that text in the button disappears and
// seem to took 0.1 of the screen rather than 0.2
Column(
verticalArragment = Arrangment.SpaceBetween
){
Text(titleText)
MyButton(
modifier = Modifier.height(
(LocalConfiguration.current.screenHeightDp * 0.2f).dp
)
)
}
2)Getting height from context.displayMetrics
// Results in almost correct on Pixel 2 and very large on Pixel 6 emulators
// So large that more than 0.2 times of the screen height
Column(
verticalArragment = Arrangment.SpaceBetween
){
Text(titleText)
MyButton(
modifier = Modifier.height(
(LocalContext.current.displayMetrics.heightPixels * 0.2f).dp
)
)
}
Additionally, MyButton is not different from the normal button provided by Compose.
Doing the same thing on SwiftUI with GeometryReader or Flutter with MediaQuery.of(context) results in the correct behaviour compared to Compose.
Any help is appreciated.
I have found my mistake even though I wrote it on the post. I am using the Button component supplied by Compose, which has its own padding. This is why it collapses itself along with the content (text) in it. I have changed it to Surface and implemented my custom button and everything worked fine.
I have a a text element with an icon to its right, both wrapped in a Row. The text has a 1.0f weight with fill = false. When a word wraps to the next line, the text has some padding at the end of it causing the icon to be too far apart from it. This is what it looks like:
App Example
Here is the code:
Row(
modifier = Modifier.width(150.dp)
) {
Text(
"John Doe John Doe John Doe",
modifier = Modifier.weight(1.0f, fill = false).background(Color.Green)
)
Icon(
imageVector = Icons.Default.Done,
contentDescription = "",
)
}
How do I make it so the text's width wraps itself without adding that extra spacing?
This is a normal behavior. It happens because you set weight for your Text and a width modifier for your Row.
It's kind of unavoidable when setting a specific width or height. It may happen even if you set weight for both Composables inside the Row (0.1f and 0.9f). Because the word can't fit in the remaining space but the Composable must fill the Row
You set the row width to 150.dp and when your Text has a weight modifier, it fills the row even if a word in your Text composable doesn't fit in the line.
I have a Row layout with two Composables inside:
Text that should wrap itself width and take as much space as possible when content is lengthy
Image that has to be present every time on the right side of Text
To achieve both, I'm currently using weight(weight = 1f, fill = false) for Text Composable. And it works fine for single line content. However, it creates an issue with line breaking and wrapping multiline text. For clearer view, I've added background(Color.Yellow) and some long words. See reference code:
Row {
Text(
text = "This is the message with quite super-unprecedented words",
modifier = Modifier
.background(Color.Yellow)
.weight(
weight = 1f,
fill = false
)
)
Image(
painter = painterResource(R.drawable.image),
contentDescription = null
)
}
And the result looks like this:
Is it possible to remove the padding at the end of Text so Image could fit closely to Text in multiline case as well? Or any other ideas how to achieve this? I've already taken a look on softWrap parameter for Text and requireSize for Image but with no big luck.
In Compose, we use AnnotatedString as a replacement for Spanned. However, I cant seem to find a way to replicate the behaviour of RelativeSizeSpan with a SpanStyle.
The relevant options I can see for SpanStyle are:
fontSize: TextUnit - not useful because this only accepts absolute text sizes, and I need my span style to scale the original font size by some factor
textGeometricTransform: TextGeometricTransform - not useful because TextGeometricTransform only performs X transformations, and I need the text to be scaled in both X and Y.
Can anyone share some insight?
You can achieve it with SpanStyle, but you need to use the em TextUnit, which is a relative font size unit. It means that 1em is equal to the current font size and 2em is a font two times bigger.
Here is the code demonstrating how it behaves on two Texts with different font size:
val annotatedString = buildAnnotatedString {
append("This is a ")
withStyle(style = SpanStyle(fontSize = 2.em)) {
append("big")
}
append(" text")
}
Column {
Text(annotatedString, fontSize = 20.sp)
Text(annotatedString, fontSize = 40.sp)
}
The word big is 2 times bigger than other words in the same Text.
You can also see that it makes the big word from first Text the same size (2 * 20sp) as the other words in the second Text (40sp).
I want to position my own component (say a Text component) vertically so that I can specify the y-offset relative to the bottom of the Text component. How could I do this in Jetpack compose?
So something like
Column {
Text("Something", modifier = Modifier.offset(y=10.dp))
}
But instead of 10dp representing the top y-position of the Text component it would be the bottom y-position. Basically taking into account the height of the Text even if Text size changes. So y = offset.y - height
As I can see it, there's two problems:
The font size can be changed, so I cannot hard code the text height.
I need to know the size of my Text component during composition, but I don't know how to get that.
You could go for custom Composables,
#Composable
fun CustomText(y: Dp){
Layout(content = { Text(text = "Lorem Ipsum") }){measurables, constraints ->
val text = measurables[0].measure(constraints)
layout(constraints.maxWidth, constraints.maxHeight){ //Change these per your needs
text.placeRelative(IntOffset(0, y.value.roundToInt() - text.height))
}
}
}
You could also use a custom Modifier. Check out using the layout modifier