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 our 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
Let’s update it to add some highlighting. Implementing Highlightable
will deserialize the _highlightResult
for each movie, and make it available through the getHighlight{s}
methods. We can then create @Transient
attributes for each highlight we want 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"))
}
We can now use these highlighted strings in our interface, for example in a MovieViewHolder
. There are three ways you can use a HighlightedString
:
- Directly as a
SpannedString
, with the highlight defaulting to bold:Copy1
TextUtils.concat(highlightedTitle?.toSpannedString(), " ($year)")
- As a customized
SpannedString
, specifying aParcelableSpan
to use as highlight style:Copy1 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:Copy1 2 3 4 5 6
// Displays actors with highlighted parts in uppercase highlightedActors?.joinToString { highlight -> highlight.tokens.joinToString("") { if (it.highlighted) it.content.toUpperCase() else it.content } }