With the booming development of mobile smart devices, a mobile multi-terminal development framework has become a general trend. Download the Flutter Analysis and Practice: Evolution and Innovation of Xianyu Technologies eBook for step-by-step analyses based on real-life problems, as well as clear explanations of the important concepts of Flutter.
The detail pages are an essential part of an e-commerce app. On the page, the major technological challenge is the hybrid text layout. Xianyu has complex and varying text layout requirements. However, in several earlier versions of Flutter, there were just simple text styles with a few configurable attributes. Even rich text implemented through TextSpan links can only display text in multiple styles, for example, a basic text segment and a link segment. These could not meet the design requirements. Therefore, development of a hybrid text layout component with more powerful features was urgently needed.
This article describes how RichText works.
1) Creation
Figure 2-14 shows the objects that are created with RichText.
Figure 2-14
LeafRenderObjectElement
instance.ComponentElement
method calls the CreateRenderObject
method of the RichText
instance to generate the RenderParagraph
instance.RenderParagraph
instance creates a TextPainter
, which is a proxy class responsible for width and height calculation and text-to-canvas rendering. In addition, TextPainter
also has a TextSpan
text structure.Finally, the RenderParagraph
instance registers itself with Dirty Nodes of the rendering module. The rendering module traverses Dirty Nodes to start RenderParagraph
rendering.
2) Rendering
As shown in Figure 2-15, the RenderParagraph
method encapsulates the logic of rendering text to the canvas by using the TextPainter
module. The calling process of RenderParagraph
is the same as RenderObject
.
Figure 2-15
During the PerfromLayout
process, TextPaint
Layout is called and AddText
is used to add text for each stage using the TextSpan
structure tree. Finally, Paragraph Layout is called to calculate the text height.
During the Paint process, clipRect
is rendered first. Then, the Paint function of TextPaint
is called to render the text through Paint of Paragraph. Finally, the drawRect
is rendered.
Based on the text rendering principle of RichText
, we can see that TextSpan
records the text information of each text segment. TextPaint
calls a native API and calculates the width and height based on the recorded information, and renders the text to the canvas. In the traditional solutions, complex hybrid layouts are rendered using HTML WebView rich text. The performance of WebView is worse than the native implementation. To solve the problem, we tried to design a native solution for hybrid image-text layouts. The initial design was to use special spans, such as ImageSpan
and EmojiSpan
to record information and use that to calculate layouts in TextPaint
Layout. Then, special widgets were rendered separately in the Paint process. However, this solution does considerable damage to class encapsulations and RichText
and RenderParagraph
source code must be replicated and modified. The final solution is to use special characters (such as an empty string) as placeholders first and move the special spans to the positions, as shown in Figure 2-16.
Figure 2-16
This solution has two challenges:
1) How can we fill the desired positions in the text and customize for the width and height we want.
u200B represents a zero width space. According to the test for TextPainter
, the width of the layout is always 0, and fontSize
only determines the height. Therefore, we use the font size with letterSpacing
in TextStyle
to control the width and height of the special characters.
/// The amount of space (in logical pixels) to add between each letter
/// A negative value can be used to bring the letters closer.
final double letterSpacing;
2) How can we move special spans to the desired positions
From the above test, it is not hard to discern that special spans are independent of Widget and RichText
. Therefore, we need to know the relative positions of the current widgets to the RichText
spans and use Stack to integrate the widgets and RichText
. We can use the getOffsetForCaret
method of TextPaint
to obtain the relative position of the current placeholder.
/// Returns the offset at which to paint the caret.
///
/// Valid only after [layout] has been called.
Offset getOffsetForCaret(TextPosition position, Rect caretPrototype)
SpaceSpan({
this.contentWidth,
this.contentHeight,
this.widgetChild,
GestureRecognizer recognizer,
}) : super(
style: TextStyle(
color: Colors.transparent,
letterSpacing: contentWidth,
height: 1.0,
fontSize:
contentHeight),
text: '\u200B',
recognizer: recognizer);
SpaceSpan
relative positions. for (TextSpan textSpan in widget.text.children) {
if (textSpan is SpaceSpan) {
final SpaceSpan targetSpan = textSpan;
Offset offsetForCaret = painter.getOffsetForCaret(
TextPosition(offset: textIndex),
Rect.fromLTRB(
0.0, targetSpan.contentHeight, targetSpan.contentWidth, 0.0),
);
........
}
textIndex += textSpan.toPlainText().length;
}
RichText
and SpaceSpans
. Stack(
children: <Widget>[
RichText(),
Positioned(left: position.dx, top: position.dy, child: child),
],
);
}
As shown in Figure 2-17, the advantage of this solution is that any widget can be integrated with RichText
through SpaceSpans
, including images, custom tags, and buttons, without affecting the encapsulation of RichText
too much.
Figure 2-17
This article only discussed rich text display, which still has limitations and places that need optimization. For example, the width and height must be specified through SpaceSpans
. In addition, neither text selection nor custom text backgrounds are supported. The rich text editor needs to support image and currency formatting during text editing.
Flutter Analysis and Practice: Multimedia Capability Expansion Best Practices
Flutter Analysis and Practice: App Framework Design Practices
56 posts | 4 followers
FollowXianYu Tech - September 8, 2020
卓凌 - September 8, 2020
XianYu Tech - September 4, 2020
Alibaba Clouder - September 21, 2020
XianYu Tech - September 7, 2020
Alibaba Tech - April 24, 2020
56 posts | 4 followers
FollowHelp enterprises build high-quality, stable mobile apps
Learn MoreAn enterprise-level continuous delivery tool.
Learn MoreProvides comprehensive quality assurance for the release of your apps.
Learn MoreAlibaba Cloud (in partnership with Whale Cloud) helps telcos build an all-in-one telecommunication and digital lifestyle platform based on DingTalk.
Learn MoreMore Posts by XianYu Tech