5

I want to change the text style (fontSize , color , fontWeight , ...) of a selected text in a TextFiled() composable , with a button in android jetpack compose.

(The main problem is, when i change the text style of a selected text ,the TextField can not save it , or when i add/remove a letter in TextField , the TextField deletes the previous text style.)

In other words, when the recomposition process occurs, the text styles disappears in the TextField()

enter image description here

my code is :

@Composable
fun Show() {

    val inputText = remember{ mutableStateOf(TextFieldValue("This is a annotated text text"))}
    Column(
        modifier = Modifier.fillMaxSize().padding(5.dp) ,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        //=================== TextField
        CustomTextField(textInput = inputText)
        //==================== Button
        Button(onClick = {
            inputText.value = changeSegmentColor(inputText.value)

        }) {
            Text(text = "Change the text style of selected text")
        }
        //======================
    }
}

@Composable
fun CustomTextField (
    textInput:MutableState<TextFieldValue>
) {
    TextField(
        value = textInput.value , onValueChange = {
            textInput.value = it
        },
        modifier = Modifier.fillMaxWidth().heightIn(min = 200.dp) ,
    )
}
private fun changeSegmentColor(textFVal: TextFieldValue):TextFieldValue{
    val txtAnnotatedBuilder = AnnotatedString.Builder()
    val realStartIndex = textFVal.getTextBeforeSelection(textFVal.text.length).length
    val endIndex = realStartIndex + textFVal.getSelectedText().length
    txtAnnotatedBuilder.append(textFVal.annotatedString)
    val myStyle = SpanStyle(
        color = Color.Red ,
        fontSize = 16.sp ,
        background = Color.Green
    )
    txtAnnotatedBuilder.addStyle(myStyle ,realStartIndex ,endIndex)
    return textFVal.copy(annotatedString = txtAnnotatedBuilder.toAnnotatedString())
}
Amir
  • 89
  • 5
  • Were you able to successfully build a `Text` Composable that displays formatted anotatedStrings? Also, provide a minimal-reproducible-example. – Richard Onslow Roper May 12 '22 at 20:04
  • 1
    Does this answer your question? [How to change TextField's highlighted text color on Jetpack Compose?](https://stackoverflow.com/questions/68779305/how-to-change-textfields-highlighted-text-color-on-jetpack-compose) – nglauber May 13 '22 at 03:25
  • @MARSK , I able to change the Style of Selected Text (like fontSize , color , ...) in Text() composable. but I do not know why the TextField() composable can not save style do so. TextField() Compoasable i an Editable text -> in Xml = EditText ... – Amir May 13 '22 at 06:20
  • @nglauber , it's good but i do not want to change the highlighted Color, i want to change the text style , suppose i want to pass a SpanStyle() to the selected Text – Amir May 13 '22 at 06:29
  • Please provide enough code so others can better understand or reproduce the problem. – Community May 13 '22 at 15:44
  • Yup, just ran into this bug my self. I'm going to log a bug about it unless you already have? – Adam Jun 19 '22 at 02:27
  • I know it's not much help, but here is already [a bug report](https://issuetracker.google.com/issues/199768107). This issue is caused by [EditingBuffer's toAnnotatedString()](https://cs.android.com/android/platform/superproject/+/androidx-main:frameworks/support/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/EditingBuffer.kt;l=315;bpv=1) creating a new AnnotatedString from the plain text version. It seems like it lacks the span support (grow, shrink, delete, etc. with text modification) that EditText has. – Jorge Martín Jul 31 '22 at 19:11

1 Answers1

0
@Composable
fun MultiStyleText(text: String, vararg styleRanges: StyleRange) {
    val annotatedString = buildAnnotatedString {
        var currentPosition = 0

        styleRanges.forEach { range ->
            val style = SpanStyle(
                color = range.textColor,
                fontSize = range.textSizeSp.sp,
                fontWeight = range.fontWeight
            )
            withStyle(style) {
                append(text.substring(currentPosition, range.endIndex))
            }
            currentPosition = range.endIndex
        }

        // Append the remaining text with the default style
        withStyle(SpanStyle()) {
            append(text.substring(currentPosition))
        }
    }

    Text(text = annotatedString)
}




data class StyleRange(
    val startIndex: Int,
    val endIndex: Int,
    val textColor: Color,
    val textSizeSp: Float,
    val fontWeight: FontWeight
)

In the above example, define a MultiStyleText composable that accepts the text argument, as well as a variable number of styleRanges of type StyleRange. Each StyleRange specifies the start and end indices of the text range to apply the style, along with the desired text color, text size, and font weight.

Inside the composable, iterate over the styleRanges and apply the corresponding style to the specified text range using withStyle. Use the append function to append the relevant substring of the text within each style range. Finally, append the remaining text with the default style.

To use the MultiStyleText composable, provide the desired text and styleRanges:

MultiStyleText(
    text = "This is a multi-style text example",
    StyleRange(0, 4, Color.Red, 18f, FontWeight.Bold),
    StyleRange(5, 7, Color.Blue, 14f, FontWeight.Normal),
    StyleRange(8, 13, Color.Green, 16f, FontWeight.Bold)
)

enter image description here

Sayan Manna
  • 584
  • 7
  • 13