Multi style text editing for TextField composable in android jetpack compose

1.9k Views Asked by At

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())
}
1

There are 1 best solutions below

0
On
@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