RI am developing an Android app using jetpack compose.
Here is a very basic UI component:
I want to add a button on the right side.
But if the name is very long, the button is gone.
My code is here:
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = rememberImagePainter(data = profileImg),
contentDescription = null,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
)
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.weight(1F) // I set the weight in here but it doesn't work.
) {
Text(
text = "very very very very very very very long name",
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = "3 minutes ago",
)
}
}
Row {
Button()
Button()
}
}
How can I show the right button correctly?
You need to actually provide that weight to Row containing your Text & make sure you don't cover the entire width. e.g don't do just 1f.
You can do something like this; (This is done with compose_version = '1.0.1')
#Composable
fun Item() {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.weight(0.7f)
) {
Image(
painter = painterResource(R.drawable.ic_launcher_background),
contentDescription = null,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
)
Column(
verticalArrangement = Arrangement.Center,
) {
Text(
text = "very very very very very very very long name",
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = "3 minutes ago",
)
}
}
Button(
onClick = {}, modifier = Modifier
.wrapContentWidth()
.weight(0.3f)
) {
Text(text = "Button")
}
}
}
Output:
Here is a working code (I've removed useless Row, it's simpler that way)
#Composable
fun Test() {
Row(
modifier = Modifier.fillMaxWidth,
horizontalArrangement = Arrangement.spacedBy(5.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = rememberImagePainter(data = profileImg),
contentDescription = null,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
)
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.weight(1f) // I set the weight in here but it doesn't work.
) {
Text(
text = "very very very very very very very long name",
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = "3 minutes ago",
)
}
Button(onClick = { }) {
Text(text = "Btn1")
}
Button(onClick = { }) {
Text(text = "Btn2")
}
}
}
Even though the other question are right I am going to explain your mistake, to better understand what is going on.
So you need:
A Row() which will contain those 3:
Image
Column
and a Row with the two buttons
In other words something like:
Row() {
Image()
Column(weight:1f)
Row()
}
Your mistake is that you created a Row with two other Rows without weights and you get this weird output.
So if you simply delete your outer Row and move your Row of buttons like so it will work:
Related
I want to align two texts to be centered vertically to the start of the TaskCard. It works as intended if there are two texts present. However, if there is only one and the other one is null the null one will completely disappear, but will still leave a blank space in its place. How do I get rid of it so I can properly align the text?
#Composable
fun TaskCard(
modifier: Modifier = Modifier,
task: Task,
viewModel: TaskListViewModel = hiltViewModel()
) {
Card(
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant
), modifier = modifier.padding()
) {
Surface(
color = MaterialTheme.colorScheme.surfaceVariant, modifier = modifier
) {
Row(
verticalAlignment = Alignment.CenterVertically, modifier = modifier.padding(12.dp)
) {
Column(
modifier = modifier
.weight(1f)
.padding(12.dp)
) {
task.categoryName?.let {
Text(
text = it,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.primary
)
}
Text(
text = task.taskName,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onBackground,
)
}
IconButton(
onClick = { viewModel.onEvent(TaskListEvent.OnEditTask(task)) },
modifier = modifier.size(36.dp)
) {
Icon(
imageVector = Icons.Rounded.Edit,
contentDescription = "Edit",
modifier = modifier.padding(horizontal = 2.dp),
tint = MaterialTheme.colorScheme.onBackground
)
}
IconButton(
onClick = { }, modifier = modifier.size(36.dp)
) {
Icon(
imageVector = Icons.Rounded.Notifications,
contentDescription = "Notifications",
modifier = modifier.padding(horizontal = 2.dp),
tint = MaterialTheme.colorScheme.onBackground
)
}
}
}
}
}
As Gabriele Mariotti suggested I've changed the condition under which the code is executed.
from:
task.categoryName?.let
to:
if (!task.categoryName.isNullOrEmpty())
I want to display a text with an icon left to the text. The text and icon should be centered horizontally. Here is a composable function for this:
Column(Modifier.fillMaxSize()) {
Row(
modifier = Modifier.align(Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically,
) {
// imagine this Box is an icon
Box(
Modifier
.size(48.dp)
.background(Color.Red)
)
Spacer(Modifier.width(8.dp))
Text(
text = "text ".repeat(3),
textAlign = TextAlign.Center,
)
}
}
It works fine with short words:
But adding long words to the text makes it too wide, and it seems that there is too much space between the icon and the text:
I've tried to add Modifier.width(IntrinsicSize.Min) to the text, and it actually solves the issue with long words:
But it breaks displaying short words:
I don't know how to make work both long and short words. Hope to get help here.
UPD:
The same result is for Android native views. Gist with xmls.
You can consider this one, all of the codes below are copy-and-paste-able.
#Composable
fun MyScreen() {
var text by remember { mutableStateOf("") }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
TextField(
modifier = Modifier.fillMaxWidth(),
value = text,
onValueChange = { text = it}
)
Spacer(modifier = Modifier.height(24.dp))
Row(
modifier = Modifier.wrapContentSize()
) {
Spacer(modifier = Modifier.weight(.5f))
SomeComposable(text = text, modifier = Modifier.weight(1f))
Spacer(modifier = Modifier.weight(.5f))
}
}
}
#Composable
fun SomeComposable(
text: String,
modifier: Modifier = Modifier
) {
Row(modifier = modifier) {
Box(
Modifier
.align(Alignment.CenterVertically)
.size(48.dp)
.background(Color.Red)
)
Spacer(Modifier.width(8.dp))
Text(
modifier = Modifier.width(IntrinsicSize.Min),
text = text,
textAlign = TextAlign.Center,
)
}
}
I just put a Spacer between the components and weighted them accordingly.
Output:
Solution proposed by my colleague.
#Composable
fun FlowText(text: String) {
FlowRow(
mainAxisSpacing = 4.dp,
mainAxisAlignment = MainAxisAlignment.Center,
crossAxisAlignment = FlowCrossAxisAlignment.Center,
) {
text.splitToSequence(' ').filter { it.isNotEmpty() }.forEach {
Text(text = it, textAlign = TextAlign.Center)
}
}
}
Demo: https://youtu.be/WXqvxlsJ3xM
I have some Column with Icon and Text inside. Column is wrap the size of Text but i want to Column wrap Icon and long text move to another line
How It's looks now
How I want it to look like
#Composable
fun ServiceItem(
service: Service,
onItemClick: (service: Service) -> Unit
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Card(
modifier = Modifier.padding(horizontal = 16.dp),
shape = RoundedCornerShape(itemBackgroundCornerSize),
backgroundColor = colorResource(id = R.color.gray)
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(itemSize)
.clickable(onClick = {
onItemClick(service)
})
) {
Image(
painter = rememberAsyncImagePainter(service.imageUrl),
contentDescription = null,
modifier = Modifier.padding(iconPadding)
)
}
}
Text(
text = service.title,
textAlign = TextAlign.Center,
style = itemTitleTextDefaultStyle(),
modifier = Modifier.padding(top = textTopPadding)
)
}
}
I have tried applying SpaceBetween, SpaceEvenly and SpaceAround but nothing seems to be working here. My main goal here is to put the iconButton and the text on the start and end of the same row. Please don't refer to me appbar for doing so I just want to know why this is not working and what is the fix?
Row(
modifier = Modifier.padding(30.dp),
horizontalArrangement = Arrangement.SpaceBetween
){
Text(
"NOTES",
fontSize = 30.sp,
fontWeight = FontWeight.Bold,
color = Color.White
)
IconButton(onClick = { /*TODO*/ }) {
Icon(
Icons.Filled.Search,
contentDescription = "Search",
tint = Color.LightGray
)
}
}
Add the modifier fillMaxWidth() in your Row
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
){
//....your content
}
In the Row modifier use fillMaxWidth()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(30.dp),
horizontalArrangement = Arrangement.SpaceBetween
)
I want to make an Image with Text on top, just like Google CLassroom. But first I want to test Image and then Text. Instead, I got the image overlapping the text. Image Overlapping text
Then I move the Image code after the text. How to get simple G classroom format
Text then Image
#Composable
fun ClassImage(
// icon: VectorAsset,
// label: String,
// modifier: Modifier = Modifier
) {
val imageAlpha = 1f
Surface(
modifier = Modifier
.padding(start = 8.dp, top = 8.dp, end = 8.dp)
.fillMaxWidth(),
color = colors.primary.copy(alpha = 0.12f)
) {
TextButton(
onClick = {},
modifier = Modifier.fillMaxWidth()
) {
Row(
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth())
{
Image(
imageResource(id = R.drawable.class1),
alpha = imageAlpha
)
Column {
Text("Alfred Sisley", fontWeight = FontWeight.Bold)
ProvideEmphasis(emphasis = EmphasisAmbient.current.medium) {
Text("3 minutes ago", style = MaterialTheme.typography.body2)
}
}
}
}
}
}
To put Text on top of the Image you can use Box, which is similar to old FrameLayout.
I'm not sure want you wanted to achieve, but if smth like this:
Then you can do it this way:
Surface(
shape = RoundedCornerShape(8.dp),
modifier = Modifier
.preferredHeight(128.dp)
.clickable(onClick = {})
) {
Box {
Image(
vectorResource(id = R.drawable.ic_launcher_background),
alpha = imageAlpha,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Column(modifier = Modifier.padding(16.dp)) {
Text(
"Alfred Sisley",
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.h6)
ProvideEmphasis(emphasis = EmphasisAmbient.current.medium) {
Text("3 minutes ago", style = MaterialTheme.typography.body2)
}
Spacer(modifier = Modifier.weight(1f))
Text(text = "Footer", style = MaterialTheme.typography.body1)
}
}
}
With 1.0.0-beta02 you can use a Box as parent container.
Something like:
Box(modifier = Modifier.height(IntrinsicSize.Max))
{
Image(
painterResource(id = R.drawable.xx),
"contentDescription",
alpha = 0.8f,
modifier = Modifier.requiredHeight(100.dp)
)
Column(
modifier = Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.Bottom) {
Text("Alfred Sisley",
fontWeight = FontWeight.Bold)
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text("3 minutes ago", style = MaterialTheme.typography.body2)
}
}
}