I highlighted the word, but not the correct word.
In my BuilderSuggection, I added like this code,
title: RichText(
text: TextSpan(
text: suggestList[index].d.substring(0, query.length),
style: TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
children: [
TextSpan(
text: suggestList[index].d.substring(query.length),
style: TextStyle(color: Colors.grey))
])),
How to highlight text using your keyboard. To highlight with the keyboard, move to the starting location using the arrow keys. Then, hold down the Shift key, and press the arrow key in the direction you want to highlight. Once everything you want is highlighted, let go of the Shift key.
I wrote a quick function that returns a List of TextSpan
.
Function matches the query string against the source string, enumerating the matches one by one, cutting the source string into pieces: before the match, after the match, and the match itself - making it bold.
It is intended to be used in a RichText
widget.
List<TextSpan> highlightOccurrences(String source, String query) {
if (query == null || query.isEmpty || !source.toLowerCase().contains(query.toLowerCase())) {
return [ TextSpan(text: source) ];
}
final matches = query.toLowerCase().allMatches(source.toLowerCase());
int lastMatchEnd = 0;
final List<TextSpan> children = [];
for (var i = 0; i < matches.length; i++) {
final match = matches.elementAt(i);
if (match.start != lastMatchEnd) {
children.add(TextSpan(
text: source.substring(lastMatchEnd, match.start),
));
}
children.add(TextSpan(
text: source.substring(match.start, match.end),
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
));
if (i == matches.length - 1 && match.end != source.length) {
children.add(TextSpan(
text: source.substring(match.end, source.length),
));
}
lastMatchEnd = match.end;
}
return children;
}
Example based on your code:
RichText(
text: TextSpan(
children: highlightOccurrences(suggestList[index].d, query),
style: TextStyle(color: Colors.grey),
),
),
Let me know if this helped.
Based on @George's answer there is a similar function with the only difference that the query
is first split by spaces and each separate word is then highlighted. It took me a while to make it work properly so why not to share:
List<TextSpan> highlightOccurrences(String source, String query) {
if (query == null || query.isEmpty) {
return [TextSpan(text: source)];
}
var matches = <Match>[];
for (final token in query.trim().toLowerCase().split(' ')) {
matches.addAll(token.allMatches(source.toLowerCase()));
}
if (matches.isEmpty) {
return [TextSpan(text: source)];
}
matches.sort((a, b) => a.start.compareTo(b.start));
int lastMatchEnd = 0;
final List<TextSpan> children = [];
for (final match in matches) {
if (match.end <= lastMatchEnd) {
// already matched -> ignore
} else if (match.start <= lastMatchEnd) {
children.add(TextSpan(
text: source.substring(lastMatchEnd, match.end),
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
));
} else if (match.start > lastMatchEnd) {
children.add(TextSpan(
text: source.substring(lastMatchEnd, match.start),
));
children.add(TextSpan(
text: source.substring(match.start, match.end),
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
));
}
if (lastMatchEnd < match.end) {
lastMatchEnd = match.end;
}
}
if (lastMatchEnd < source.length) {
children.add(TextSpan(
text: source.substring(lastMatchEnd, source.length),
));
}
return children;
}
The usage is the same as with @George's answer:
RichText(
text: TextSpan(
children: highlightOccurrences(suggestList[index].d, query),
style: TextStyle(color: Colors.grey),
),
),
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With