API Reference / InstantSearch Android / Highlighting

About this widget

A great search interface highlights parts of the search results to explain why they are relevant to the user. With InstantSearch Android, the Highlightable interface and HighlightedString objects simplify highlighting the right words in a search response that match your query.

You can read more about the concept of highlighting in the highlighting guide.

Examples

Lets take the example of an index containing movies. Each movie record consists of two fields: title and year. Here is what the search engine response for a query "red" could look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
  "title": "The Shawshank Redemption",
  "year": 1994,
  "genre": ["action", "adventure"],
  "actors": ["Tim Robbins", "Morgan Freeman"],
  "objectID": "439817390",
  "_highlightResult": {
    "title": {
      "value": "The Shawshank <em>Red</em>emption",
      "matchLevel": "full",
      "fullyHighlighted": false,
      "matchedWords": [
        "red"
      ]
    }
  }
}

To display those movies in your interface, you likely have created a data class that looks something like the following:

1
2
3
4
5
6
7
@Serializable
data class Movie(
    val title: String,
    val year: String,
    val genre: List<String>,
    override val objectID: ObjectID,
) : Indexable

Update it to add some highlighting. Implementing Highlightable will deserialize the _highlightResult for each movie, and make it available through the getHighlight{s} methods. Create @Transient attributes for each highlight to display, being either single values or lists:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Serializable
data class Movie(
    val title: String,
    val year: String,
    val genre: List<String>,
    override val objectID: ObjectID
    override val _highlightResult: JsonObject?
) : Indexable, Highlightable {
  
  @Transient
  public val highlightedTitle: HighlightedString?
      get() = getHighlight(Attribute("title"))

  @Transient
  public val highlightedGenres: List<HighlightedString>?
      get() = getHighlights(Attribute("genre"))

  @Transient
  public val highlightedActors: List<HighlightedString>?
      get() = getHighlights(Attribute("actors"))
}

Use these highlighted strings in the interface, for example in a MovieViewHolder. There are three ways you can use a HighlightedString:

Using highlighted strings in an Android view

  • Directly as a SpannedString, with the highlight defaulting to bold:
    1
    
    TextUtils.concat(highlightedTitle?.toSpannedString(), " ($year)")
    
  • As a customized SpannedString, specifying a ParcelableSpan to use as highlight style:
    1
    2
    
     highlightedGenres?.toSpannedString(BackgroundColorSpan(Color.YELLOW))
         ?: buildSpannedString { italic { append("unknown genre") } }
    
  • Any way you want, iterating on HighlightedString#tokens to process it however you like:
    1
    2
    3
    4
    5
    6
    
     // Displays actors with highlighted parts in uppercase
     highlightedActors?.joinToString { highlight ->
            highlight.tokens.joinToString("") {
                if (it.highlighted) it.content.uppercase() else it.content
            }
        }
    

Compose UI

  • Directly as a AnnotatedString, with the highlight defaulting to bold:
    1
    
      highlightedTitle?.toAnnotatedString()
    
  • As a customized AnnotatedString, specifying a SpanStyle to use as highlight style:
    1
    2
    
      highlightedGenres?.toAnnotatedString(SpanStyle(background = Color.Yellow))
          ?: AnnotatedString("unknown genre", SpanStyle(fontStyle = FontStyle.Italic))
    
  • Any way you want, iterating on HighlightedString#tokens to process it however you like:
    1
    2
    3
    4
    5
    6
    
      // Displays actors with highlighted parts in uppercase
      highlightedActors?.joinToString { highlight ->
          highlight.tokens.joinToString("") {
              if (it.highlighted) it.content.uppercase() else it.content
          }
      }
    
Did you find this page helpful?