Last updated:
0 purchases
rich text controllerx
rich_text_controller #
Text editing controller highlighting words, prefixes and suffixes based on RegExps and Strings.
User callback for all matched highlights
User callback for tapped highlights
User callback for selected highlights
User callback for constructing complex InlineSpans
Deletes highlights on backspace
Exact word, prefix, postfix matching
Disable highlighting and callbacks dynamically
Installation #
flutter pub add rich_text_controllerx
copied to clipboard
Quick Start #
MatchTargetItem
MatchTargetItem defines words or paterns to match and the TextStyle for matched words or patterns.
The optional function MatchTargetItem.onSelected is invoked when a matched words is selected.
The optional function MatchTargetItem.onTapInto is invoked when a matched words is tapped into. The needed minimum difference in cursor position is two chars.
Combining MatchTargetItem.onSelected and MatchTargetItem.onTapInto might not be useful.
MatchTargetItem.matchString offers various String matching patterns:
enum StringMatch {
any, // No word boundaries, also inside a String
prefix, // The beginning of a String
postfix, // The beginning of a String
prefixComplete, // The beginning of a String and the complete word
postfixComplete, // The end of a String and the complete word
exact, // The exact String within its own word boundaries
}
copied to clipboard
MatchTargetItem.matchPayload allows to set a custom payload, accessible in MatchResultItem.target.matchPayload.
MatchTargetItem.inlineSpanBuilder allows to define a custom function returning the InlineSpan to show. Useful for displaying tooltips etc.
RichTextController
The optional function RichTextController.onMatch is invoked everytime the set of matched words change.
late final RichTextController controller = RichTextController(
text:
'Home sweet home! Do good homework and housework at home. The happyness of an ending.',
sortTargetsByPatternLength: true,
mergeOverlappingStyles: true,
deleteOnBack: true,
enableHighlight: true, // toggable at runtime
enableOnTapInto: true, // toggable at runtime
enableOnSelected: true, // toggable at runtime
onMatch: (List<MatchResultItem> matches) {
for (final MatchResultItem match in matches) {
log(match.toString());
}
},
targets: [
// --------------------------------------------------------------
// SINGLE STRING
// --------------------------------------------------------------
MatchTargetItem.string(
'homework',
style:
const TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
stringMatch: StringMatch.exact,
caseSensitive: false,
onSelected: (MatchResultItem match) => _onWordMatchSelected(match),
onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
),
MatchTargetItem.string(
'Home',
style: const TextStyle(color: Colors.red),
stringMatch: StringMatch.any,
caseSensitive: false,
onSelected: (MatchResultItem match) => _onWordMatchSelected(match),
onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
),
// Prefix
MatchTargetItem.string(
'happy',
style: const TextStyle(color: Colors.blue),
stringMatch: StringMatch.prefix,
caseSensitive: false,
onSelected: (MatchResultItem match) => _onWordMatchSelected(match),
onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
),
// Postfix
MatchTargetItem.string(
'ing',
style: const TextStyle(color: Colors.blue),
stringMatch: StringMatch.postfix,
caseSensitive: false,
onSelected: (MatchResultItem match) => _onWordMatchSelected(match),
onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
),
// --------------------------------------------------------------
// MULTIPLE STRINGS
// --------------------------------------------------------------
MatchTargetItem.strings(
['do', 'at'],
style: const TextStyle(color: Colors.pink),
onSelected: (MatchResultItem match) => _onWordMatchSelected(match),
onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
),
// --------------------------------------------------------------
// SINGLE REGEXP
// --------------------------------------------------------------
MatchTargetItem.regex(
RegExp(r'sweet'),
style: const TextStyle(color: Colors.indigo),
onSelected: (MatchResultItem match) => _onWordMatchSelected(match),
onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
),
// --------------------------------------------------------------
// MUTIPLE REGEXPs
// --------------------------------------------------------------
MatchTargetItem.regexes(
[RegExp(r'good'), RegExp(r'and')],
style: const TextStyle(
decoration: TextDecoration.underline,
decorationStyle: TextDecorationStyle.wavy,
decorationColor: Colors.indigo,
decorationThickness: 3,
),
onSelected: (MatchResultItem match) => _onWordMatchSelected(match),
onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
),
],
);
// ...
TextField(controller: controller)
copied to clipboard
RichWrapper
RichWrapper(
initialText: 'Good morning and good night at Github',
targets: [
MatchTargetItem.string('good',
style: const TextStyle(color: Colors.red)),
MatchTargetItem.strings(['morning', 'night'],
style: const TextStyle(color: Colors.blue)),
MatchTargetItem.regex(RegExp(r'and'),
style: const TextStyle(color: Colors.orange)),
MatchTargetItem.regexs([RegExp(r'at'), RegExp(r'Github')],
style: const TextStyle(color: Colors.indigo)),
],
child: (controller) => TextField(controller: controller),
)
copied to clipboard
InlineSpan-Builder
The [inlineSpanBuilder] is an optional custom builder. In the example below,
it returns a WidgetSpan showing aTooltip.
If the [inlineSpanBuilder] is null, highlighting is done as per [style]
definition in MatchTargetItem.
MatchTargetItem.strings(
['thing', 'it', 'there was', 'used to'],
style: TextStyle(color: Colors.red),
stringMatch: StringMatch.exact,
///
/// A custom payload, may be `null`.
///
matchPayload: WritingAidItem(
'Vague words: Underspecified',
'Not providing concrete information',
),
///
/// InlineSpanBui8uilder returns a `WidgetSpan` with `Tooltip`.
/// The `Tooltip` is based on the object defined in [matchPayload].
///
inlineSpanBuilder: (
String match,
TextStyle matchStyle,
WritingAidItem? matchPayload) {
InlineSpan ret = TextSpan(text: match, style: matchStyle);
if (matchPayload != null) {
final TextSpan toolTipRichMessage = TextSpan(
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(color: Colors.white),
children: [
TextSpan(
text: match,
style: const TextStyle(fontStyle: FontStyle.italic)),
const TextSpan(text: '\n'),
TextSpan(
text: matchPayload.category,
style: const TextStyle(fontWeight: FontWeight.bold)),
const TextSpan(text: '\n'),
TextSpan(
text: matchPayload.description,
style: const TextStyle(fontStyle: FontStyle.normal)),
]);
ret = WidgetSpan(
child: Tooltip(
richMessage: toolTipRichMessage,
child: Text(match, style: matchStyle)));
}
return ret;
}
),
copied to clipboard
Example #
See the example app in example/flutter_example for code.
Inspiration #
This package is a complete rewrite of https://github.com/micazi/rich_text_controller.
License #
This project is licensed under the MIT License - see the LICENSE.md file for details
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.