Home > Back-end >  dynamically change textDecoration on clickableText android compose
dynamically change textDecoration on clickableText android compose

Time:09-17

I have a large number of texts in a row, and I would like to make every one of them change text decoration on press

(so the user can notice which text/tag is already selected)

(unselected: TextDecoration.None, selected: TextDecoration: Underlined)

(user can press selected text to unselect it)

var tagsSelected = mutableListOf<String>()

...
Text(text = "tech",
                    Modifier.clickable {
                    if (tagsSelected.contains("tech")) {
                        tagsSelected.remove("tech")
                        // RemoveTextDecoration ?
                    } else {
                        tagsSelected.add("tech")
                        // AddTextDecoration ?
                    }
                }.padding(5.dp))
...

I've tried using variables (not a good idea cause it would require a lot of them), using an mutable array of boolean values (later observed as states) and none of that has brought results for me,

any amount of help will be appreciated,

thanks :)

CodePudding user response:

You're creating a new mutableListOf on each recomposition. That's why new values are not getting saved. Check out how you should store state in compose.

rememberSaveable will save your state even after screen rotation(unlike remember), and mutableStateListOf is a variation of mutable list which will notify Compose about updates. I you need to save state even when you leave the screen and come back, check out about view models.

Also you can move your add/remove logic into extension so your code will look cleaner:

fun <E> MutableList<E>.addOrRemove(element: E) {
    if (!add(element)) {
        remove(element)
    }
}

Final variant:

val tagsSelected = rememberSaveable { mutableStateListOf<String>() }

Text(
    text = "tech",
    modifier = Modifier
        .clickable {
            tagsSelected.addOrRemove("tech")
        }
        .padding(5.dp)
    )

If you have many Text items which looks the same, you can repeat them using forEach:

val tagsSelected = rememberSaveable { mutableStateListOf<String>() }
val items = listOf(
    "tech1",
    "tech2",
    "tech3"
)
items.forEach { item ->
    Text(
        text = item,
        modifier = Modifier
            .clickable {
                tagsSelected.addOrRemove(item)
            }
            .padding(5.dp)
    )
}

If you need to use selection state only to change text decoration, you can easily move it to an other composable and create a local variable:

@Composable
fun ClickableDecorationText(
    text: String,
) {
    var selected by rememberSaveable { mutableStateOf(false) }
    Text(
        text = text,
        textDecoration = if(selected) TextDecoration.Underline else TextDecoration.None,
        modifier = Modifier
            .clickable {
                selected = !selected
            }
            .padding(5.dp)
    )
}
  • Related