androidlistparsingandroid-jetpack-composefull-text-search

Using Jetpack Compose, how do you develop a feature that highlights characters within a string that match text field input?


How do you develop a feature that changes the color of characters within a string that match the text entered into a text field, using Jetpack Compose?

This is a common feature in applications that allow users to search through a list using a search bar and returning matching results. The characters within the list item that match the text entered into a search bar will be a different color than the characters that don't match.

The only problem is that I can't quite feature out how to implement that feature properly. I have developed a feature that comes very close to achieving that goal but ever so slightly falls short.

Here is the code for what I have accomplished so far.

val searchValue by remember {mutableStateOf(TextFieldValue(""))}
val nameList = listOf("John", "Brittany", "Rick", "Jill", "Eric", "Alex", "Aaron")


Scaffold(
        topBar = {
            // SEARCH BAR; THE LIST IS RECOMPOSED ON EVERY INPUT
            TextField(
                value = searchValue,
                onValueChange = {
                    searchValue = it
                    nameList.filter { it.contains(searchValue.text, ignoreCase = true) }
                })
        }
    ) {padding ->
        LazyColumn(
            modifier = Modifier.padding(padding)
        ) {

            // DISPLAYED LIST OF MATCHING NAMES
            items(if (searchValue.text.isEmpty()) emptyList() else nameList.filter { it.contains(searchValue.text, ignoreCase = true) }) { name ->

               Text(
                   // ANNOTATED STRING THAT PARSES EACH CHARACTER IN A LIST ITEM
                   buildAnnotatedString {
                       name.forEach { letterInName ->
                           // IF THE CHARACTER MATCHES THEN THE TEXT CHANGES TO BLUE
                           if (letterInName.toString() in searchValue.text) {
                              withStyle(style = SpanStyle(color = Color.Blue)) { append(letterInName.toString()) }
                           // ELSE BLACK
                           } else {
                              withStyle(style = SpanStyle(color = Color.Black)) { append(letterInName.toString()) }
                           }
                           }
                   }
               )

            }

        }
    }

This system almost accomplishes what I want but there is one problem. If there is a sequence of characters in a row that are the same, they all will be highlighted regardless of how many characters are in the search bar.

For example, in the name "Jill" both "L"s will be highlighted even if there is only one "L" in the search bar. The same problem occurs with the "A" in "Aaron", both will be highlighted regardless of how many are in the search bar.

How can I fix this problem. Making sure only the number amount of a specific character entered into the search bar are highlighted.

Thanks for taking the time to read this question.


Solution

  • A developed the same functionality some time ago, you can find it here