Zero, preface,
Through the first four articles, we have understood the source code implementation and basic use of Text. Its essence is built with RichText, that is to say, understanding Text is equivalent to understanding RichText. Text. Rich is also an easy way to build rich Text components. In the third article, we introduced Text. This article is not related to the previous ones and can be eaten on its own.
- The Flutter component | Text Text reading (a)”
- (2) the Flutter component | Text Text reading”
- (3) the Flutter component | Text Text reading”
- (4) the Flutter component | Text Text reading”
1. Meet Linespan
1. What does Text. Rich do
Inside the Text component is a textSpan member of type InlineSpan. It can only be assigned via the text.rich construct. When using the plain Text construct, this member is null.
-- -- -- - > [Text source] -final InlineSpan textSpan;
const Text.rich(
this.textSpan, {
/ /... slightly
Copy the code
This member, if non-empty, is used in Text#build as the children of TextSpan in RichText to implement RichText.
2. What is InlineSpan
InlineSpan is an abstract class, so we need to subclass it. The implementation classes include TextSpan and WidgetSpan, which are used to implement various text styles and add components to text, respectively.
For the following requirements, we need to use TextSpan. In a TextSpan, we can pass List
to get a tree structure. The implementation code is as follows:
class HomePage extends StatelessWidget {
final TextStyle linkStyle = const TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
decorationColor: Colors.blue);
final TextStyle defaultStyle = const TextStyle(
color: Colors.black);
@override
Widget build(BuildContext context) {
InlineSpan span = TextSpan(children: [
TextSpan(text: 'I have agreed', style: defaultStyle),
TextSpan(text: Terms of Service, style: linkStyle),
TextSpan(text: ' 和 ', style: defaultStyle),
TextSpan(text: Privacy Policy, style: linkStyle),
TextSpan(text: ' 。', style: defaultStyle),
]);
returnText.rich(span); }}Copy the code
3. Click events in InlineSpan
There is a recognizer member in the InlineSpan, of type GestureRecognizer. It is an abstract class with many implementation classes, and we can choose different implementation classes according to different gestures.
Click events can use TapGestureRecognizer, which can listen for press, click, lift, cancel and other events. So we can click listen on an InlineSpan. The effect is as follows:
In this way, the method can be executed when clicked to jump to the corresponding clause interface. Please note that the GestureRecognizer object needs to do its dispose operation. The code is as follows:
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextStyle linkStyle = const TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
decorationColor: Colors.blue);
final TextStyle defaultStyle = const TextStyle(color: Colors.black);
TapGestureRecognizer _tapServer;
TapGestureRecognizer _tapPolicy;
@override
void initState() {
super.initState(); _tapServer= TapGestureRecognizer().. onTap=(){print('Click on Terms of Service'); }; _tapPolicy= TapGestureRecognizer().. onTap=(){print('Click on privacy Policy');
};
}
@override
void dispose() {
_tapServer.dispose(); // Destroy the object
_tapPolicy.dispose(); // Destroy the object
super.dispose();
}
@override
Widget build(BuildContext context) {
InlineSpan span = TextSpan(children: [
TextSpan(text: 'I have agreed', style: defaultStyle),
TextSpan(text: Terms of Service, style: linkStyle, recognizer: _tapServer),
TextSpan(text: ' 和 ', style: defaultStyle, ),
TextSpan(text: Privacy Policy, style: linkStyle,recognizer: _tapPolicy),
TextSpan(text: ' 。', style: defaultStyle),
]);
returnText.rich(span); }}Copy the code
4. WidgetSpan
With WidgetSpan you can add any Widget to your text, such as the image below.
@override
Widget build(BuildContext context) {
final Image image = Image.asset(
'assets/images/icon_head.webp',
width: 20,
height: 20,); InlineSpan span = TextSpan(children: [ WidgetSpan(child: image,), TextSpan(text:'I have agreed', style: defaultStyle),
TextSpan(text: Terms of Service, style: linkStyle, recognizer: _tapServer),
TextSpan(text: ' 和 ', style: defaultStyle,),
TextSpan(text: Privacy Policy, style: linkStyle, recognizer: _tapPolicy),
TextSpan(text: ' 。', style: defaultStyle),
]);
return Text.rich(span);
}
Copy the code
An PlaceholderAlignment alignment and a Baseline TextBaseline can be set in WidgetSpan. If alignment contains baseline, TextBaseline must be set. The six alignments are as follows:
At this point, we’ve briefly looked at the use of linespan to implement rich text.
Second, local text highlighting
We use linespan for small text pieces, but for large text displays, it is impractical to assemble them yourself. In this case, the string needs to be parsed according to certain rules, and then InlineSpan is generated uniformly.
1. String parsing
Let’s start with the following paragraph, some of which is highlighted. You can define a rule and then parse it.
Although we can define our own rules, we already have rules in.md, and it is best to use common rules as follows.
The first thing we need to do is find the string that is enclosed in backquotes, and we’ll do the text parsing by writing a StringParser class. The StringScanner is used to scan the text, and the following re is used to parse the position of the wrapped text.
class StringParser {
final String content;
StringParser({this.content});
StringScanner _scanner;
parser() {
_scanner = StringScanner(content);
parseContent();
}
void parseContent() {
while(! _scanner.isDone) {if (_scanner.scan(RegExp('`. *? ` '))) {
print(content.substring(_scanner.lastMatch.start+1,_scanner.lastMatch.end- 1));
}
if(! _scanner.isDone) { _scanner.position++; }}}}Copy the code
2. Define the highlight data type
We store the information needed by linespan by having a SpanBean. Specify the supported text style types through TextStyleSupport.
class SpanBean {
SpanBean(this.start, this.end);
final int start;
final int end;
String text(String src) {
return src.substring(start+1, end- 1);
}
TextStyle get style => TextStyleSupport.dotWrapStyle;
}
class TextStyleSupport{
static const defaultStyle = TextStyle(color: Colors.black,fontSize: 14);
static const dotWrapStyle = TextStyle(color: Colors.purple,fontSize: 14);
}
Copy the code
In parseContent, you can then save the parsed useful information to SpanBean and maintain it with collections.
List<SpanBean> _spans = [];
void parseContent() {
while(! _scanner.isDone) {if (_scanner.scan(RegExp('`. *? ` '))) {
int startIndex = _scanner.lastMatch.start ;
int endIndex = _scanner.lastMatch.end ;
_spans.add(SpanBean(startIndex, endIndex));
}
if(! _scanner.isDone) { _scanner.position++; }}}Copy the code
3. Generate InlineSpan from the SpanBean collection
Traverses the SpanBean collection, setting only the default style outside of it, and the text within its range to the specified style.
InlineSpan parser() {
_scanner = StringScanner(content);
parseContent();
final List<TextSpan> spans = <TextSpan>[];
int currentPosition = 0;
for (SpanBean span in _spans) {
if(currentPosition ! = span.start) spans.add(TextSpan(text: content.substring(currentPosition, span.start))); spans.add(TextSpan(style: span.style, text: span.text(content))); currentPosition = span.end; }if(currentPosition ! = content.length) spans.add(TextSpan(text: content.substring(currentPosition, content.length)));return TextSpan(style: TextStyleSupport.defaultStyle, children: spans);
}
Copy the code
Use 4.
So StringParser# Parser gets the InlineSpan and displays it. This completes our need for a simple package highlighting. It’s also very easy to use, sometimes just to highlight something, there’s no need to use the library parsed by Markdown, which is a hundred lines of code. By writing it out yourself, you can have a deeper understanding of what’s going on inside, and if you want to change the style, you can do it easily.
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
InlineSpan span;
final String content = "" Perhaps the first reaction to Flutter painting is to use the 'CustomPaint' component to create a custom 'CustomPainter' object. All visible components of a Flutter, such as Text, Image, Switch, Slider, etc., are drawn from their roots. However, a look at the source code shows that most of the components of a Flutter are not drawn using the 'CustomPaint' component. The 'CustomPaint' component is a wrapper around the underlying painting of the framework. This series is an exploration of Flutter drawing, using 'testing', 'debugging' and 'source code analysis' to reveal things that were' overlooked 'or' never known 'at the time of drawing, and points that could be problematic if omitted. "" ";
StringParser parser;
@override
void initState() {
super.initState();
parser = StringParser(content: content);
span = parser.parser();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(20.0), child: Text.rich(span), ); }}Copy the code
Such a simple wrapping highlighting text is implemented, and if you want to create your own parsing rules, you can customize them, which is the freedom of the creator. That’s all for this article, and we’ll continue to expand text parsing in future articles, such as link parsing and some basic syntax for Markdown. In this way, Text is not only simple as Text, but also involves higher-order skills such as string parsing and the use of re.
Once we’ve mastered these capabilities, we’ll be able to go back and look at the implementation of code highlighting. Moving to another platform, web, Android, etc., we just need to know how to parse, the whole process is similar, this is experience and ability, like drawing, these skills do not fade away with the fall of the framework, you know, it is yours. That’s all for this article. Thank you for watching
@Zhang Fengjietele 2021.01.20 not allowed to transfer my public number: the king of programming contact me – email :[email protected] – wechat :zdl1994328 ~ END ~