4

I'm currently working on a button, which has 3 elements: An icon (with a fixed size), a title (f.e Buy Now!) and the price of the item. The price which should be displayed is adaptive, this could be €2,00 or €2000,00. The title is supposed to be centered, based on the Button itself, rather than the area it can occupy.

The price of object has the priority within the button, and should always be fully displayed with a set style. Due to this, the size of this object is variable, and can not be determined beforehand.

When the length of the price object increases, naturally the available space of the title decreases. However, when attempting to center the text, I could only get it to center based on the available space, which resulted in the text being off-center. Rough wireframes

How could one approach this issue, allowing for the text to be centered based on the parent (button), rather than the available text size?

z.g.y
  • 5,512
  • 4
  • 10
  • 36
Bart P
  • 93
  • 4
  • For this you can use ConstraintLayout Have you tried? – Vahid Garousi Nov 09 '22 at 15:26
  • I did not know Jetpack Compose had Constraintlayout, so I'll make sure to look into that. I am however, not very experienced with XML either, and I wouldn't know how to do it with the XML Constraintlayout, let alone the Jetpack Compose version. If you have an idea as to how it would work, I'd appreciate a (possibly simplified) example which I could reference and implement by myself! – Bart P Nov 09 '22 at 15:43
  • Of course, wait a little – Vahid Garousi Nov 09 '22 at 15:46

2 Answers2

3

I tried to prepare an understandable example for you, if it was useful, please select my answer as the correct answer

enter image description here


import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.AppBarDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.ConstraintSet
import androidx.constraintlayout.compose.Dimension
import stackoverflow.answers.ui.theme.StackOverflowAnswersTheme


@Composable
private fun StandardToolbar(
    onProfileButtonClick: () -> Unit,
    onFilterButtonClick: () -> Unit,
    onBackButtonClick: () -> Unit
) {
    val constraintSet = ConstraintSet {
        val startReference = createRefFor("startReference")
        val endReference = createRefFor("endReference")
        val titleReference = createRefFor("titleReference")
        constrain(startReference) {
            start.linkTo(parent.start, 16.dp)
            top.linkTo(parent.top, 16.dp)
            bottom.linkTo(parent.bottom, 16.dp)
            width = Dimension.value(48.dp)
        }
        constrain(endReference) {
            end.linkTo(parent.end, 16.dp)
            top.linkTo(parent.top, 16.dp)
            bottom.linkTo(parent.bottom, 16.dp)
            width = Dimension.value(48.dp)
        }
        constrain(titleReference) {
            start.linkTo(startReference.end, 8.dp)
            end.linkTo(endReference.start, 8.dp)
            top.linkTo(parent.top, 16.dp)
            bottom.linkTo(parent.bottom, 16.dp)
            width = Dimension.fillToConstraints
        }
    }
    Surface(
        elevation = AppBarDefaults.TopAppBarElevation,
        shape = RoundedCornerShape(
            bottomStart = 50f,
            bottomEnd = 50f
        ),
        color = Color(0XFF2F364E),
        modifier = Modifier
            .fillMaxWidth()
            .height(72.dp)
    ) {
        ConstraintLayout(
            modifier = Modifier.fillMaxSize(),
            constraintSet = constraintSet
        ) {
            Box(
                modifier = Modifier
                    .layoutId("startReference")
                    .size(48.dp)
                    .background(Color.Blue)
            ) {

            }
            Text(
                modifier = Modifier
                    .layoutId("titleReference"),
                text = "Title",
                style = MaterialTheme.typography.h5.copy(fontWeight = FontWeight.Bold),
                color = Color.White,
                overflow = TextOverflow.Ellipsis,
                textAlign = TextAlign.Center,
                maxLines = 1
            )
            Box(
                modifier = Modifier
                    .layoutId("endReference")
                    .size(48.dp)
                    .background(Color.Green)
            ) {
                Text(text = "E 20,000", modifier = Modifier.align(Alignment.Center), style = MaterialTheme.typography.caption)
            }
        }
    }
}


@Composable
@Preview
fun StandardToolbarPreview() {
    CompositionLocalProvider(
        LocalLayoutDirection provides LayoutDirection.Ltr
    ) {
        StackOverflowAnswersTheme {
            StandardToolbar(
                onProfileButtonClick = { },
                onFilterButtonClick = { },
                onBackButtonClick = {}
            )
        }
    }
}
Vahid Garousi
  • 546
  • 4
  • 17
  • Thanks for the worked out example! It does not entirely do what I wished to do, but it was a useful reference as to how Constraintlayout could be used aswell! – Bart P Nov 10 '22 at 07:50
1

You can try this:

Button(
    modifier = Modifier
      .wrapContentHeight()
      .padding(horizontal = 8.dp),
    onClick = {}
) {
      Row(
          modifier = Modifier.fillMaxWidth(),
          verticalAlignment = Alignment.CenterVertically,
          horizontalArrangement = Arrangement.SpaceAround
      ) {

           Box(
               modifier = Modifier.weight(1f),
               contentAlignment = Alignment.TopStart
           ) {
               Icon(
                  imageVector = Icons.Default.ImageSearch,
                  contentDescription = null
               )
           }

           Box(
               modifier = Modifier.weight(1f),
               contentAlignment = Alignment.Center
           ) {
               Text(
                     text = "Buy Now"
               )
           }

           Box(
                modifier = Modifier.weight(1f),
                contentAlignment = Alignment.TopEnd
           ) {
               Text(
                   text = "€ 2.00"
                 // text = "€ 2000.00"
               )
           }
       }
 }

enter image description here

The Button has a content parameter you can use to set its content, in this case we use a Row to set contents in the horizontal axis.

Note that each of the components, Icon Text and Text are wrapped inside a Box with a weight of 1f, making each those boxes as their container that also takes equal divided space of the parent Row.

The middle Box positions its child in the center, while the first and last Box positions their children (i.e Icon and Text) in TopStart and TopEnd alignment, though you don't need to worry the "top" positioning as its neglected here because the parent Row aligns all its children center-vertically

If we put a background color on each Box,

Modifier.background(Color.LightGray/Gray/DarkGray)

we can clearly see their equal width

enter image description here

z.g.y
  • 5,512
  • 4
  • 10
  • 36
  • 1
    Thanks for the answer! I ended up modifying it a little, including some extra padding and text overflow, but it did exactly what I was looking for! – Bart P Nov 10 '22 at 07:51