2

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:

few small words many small 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:

long words

I've tried to add Modifier.width(IntrinsicSize.Min) to the text, and it actually solves the issue with long words:

long words are fixed!

But it breaks displaying short words:

but short words are broken...

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.

Eugene.D
  • 81
  • 5
  • weird, I tested your code with very long text (as one word), and got the same result as in the first image – Paul Sizon Dec 06 '22 at 21:54
  • Yeah, it looks fine with a very long word. The text view takes all the available space, and the text is broken into lines in any part of the word. But if there are, let's just say, "middle length" words, then the text view still occupies all the available space, but the text is broken into lines by white spaces. Thus, there is an extra unused space in the left and in the right of the view. – Eugene.D Dec 06 '22 at 22:52

2 Answers2

1

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:

enter image description here

z.g.y
  • 5,512
  • 4
  • 10
  • 36
  • Thank you for the asnwer. I copied your code and [it works weird](https://youtube.com/shorts/pHixFOlfMjQ?feature=share). Also on the gif you are typing a single very long word. My original code handles this case right. – Eugene.D Dec 07 '22 at 21:16
  • So you just want to make the start and end of the words clipped to the edges right? Have you tried using TextAlign.Justified or TextAlign.Start? using the codes in my answer? – z.g.y Dec 07 '22 at 23:30
1

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

Eugene.D
  • 81
  • 5