A flutter rich text scheme with easy migration and high compatibility


Introduction:Flutter rich text evolution

Author: leisure fish technology – Shinjuku


In the idle fish message system, rich text accounts for a very large proportion in the UI side. Recently, the news part is being fluttered as a whole. How to solve the problem of rich text on the side of flutter has become a risk point in the early stage of the project.

In native, the message uses HTML protocol to carry the parsing and presentation of rich text. Because the historical data of the message has the characteristics of falling into the database, we must be compatible with this protocol on the flutter side. Can we expand and improve the capabilities of flutter on the basis of compatibility?

At present, Xianyu is also upgrading flutter 1.12, so we not only need to support mixed text and text layout in the current version, but also need to quickly migrate to a higher version of the system solution. Therefore, we need to find a rich text solution with high compatibility and easy migration.

Industry status

In the industry, there are solutions for the old version of richtext (before flutter 1.7.3). For details, please refer to Xuanchuan: “how to realize flutter rich text at low cost, this article is enough!”. But there is no solution to the whole link of rich text, and the richtext of flutter itself is evolving with the version iteration, so we need a complete evolution scheme.

In fact, richtext from flutter 1.7.3 has solved many of our problems. How is it implemented? What’s the difference between the implementation and the old one? With the problem, let’s first analyze its implementation principle.

The principle of richtext mixed layout

Since flutter 1.7.3, richtext no longer inherits from leafrenderobjectwidget, but from multichildrenderobjectwidget. It is easy to see that richtext will be a layout control with multiple child controls.

Creation process:

A flutter rich text scheme with easy migration and high compatibility

As shown in the figure above, the text parameter we pass to richtext is inlinespan, and textspan and widgetspan are its subclasses.

  1. In the process of richtext initialization, all widgetspan in the text will be recursively filtered out and passed to the parent class multichildrenderobjectwidget.
  2. Create a multichildrenderobjectelement, and then richtext will generate a renderparagraph by creating a renderobject.
  3. During the initialization of renderpragraph, textpainter will be created, which is the core of rendering. Layout, paint and event distribution operations will be performed here; Then recursively filter the placeholderspan (in fact, widgetspan).
Render pass:

A flutter rich text scheme with easy migration and high compatibility

The figure above shows the performlayout function in renderpragraph.

  1. As shown in the figure above, render paragraph executes performlayout. First of all_ Layoutchildren: lay out the child controls to get the size of the child controls. If there are no child controls, return directly. The child control here is widgetspan.
  2. Step two_ Layouttextwithconstraints is to execute_ The layout method of textpainter, where text (inlinespan) is used to build, will be traversed and executed according to its tree structure.

    1. When textwidget builds, it will add its own text (this is a real string) to the builder.
    2. When widgetspan builds, it will add the placeholder dimensions information of its own control to the builder. This is actually to add a placeholder, which will be the same size as the control.
    3. Next_ The paragraph will make a layout, and then get each place to store it.
  3. In the paint process, the text with a placeholder will be drawn first, and then the sub control will be traversed to set the offset according to the position of the placeholder obtained in steps 2-3.

Generally speaking, compared with the old version, the new version has more bottom layers_ Addplaceholder capability, which is used to occupy the widget of mixed layout and obtain the location information.

Design ideas

We take HTML protocol as the starting point, which can not only solve the parsing and rendering of ordinary HTML strings, but also expand the ability of user-defined Emoji strings. The following figure shows the general design idea:

A flutter rich text scheme with easy migration and high compatibility

The current message display is divided into two scenarios. One is a string with a free fish’s custom Emoji expression

Hello [smile], your baby is good [bares teeth], is it postal[ Bad laugh

The other is a simple HTML string:

"< font color =" #888888 "> the whole trading process is idle, < / font > < strong > < font color =" #f54444 "> you dare to buy, I dare to pay</ Font > < / strong > < font color = { 888888 > < font > < strong > < font color = { f54444 > > in case of loss of money and goods due to fraud, the maximum compensation is RMB 5000 < / font > < / strong > < strong > < font color = { f54444 > < / font > < / strong >“

Of course, there is the most common plain text.

For these three kinds of strings, the server does not use the type to distinguish us. What the client gets is a string. How to deal with the end side and display it efficiently?

The process is designed as follows:

  1. First of all, for the controls that are determined to be pure text, the richtext of single textspan is directly used without the encapsulation of text.
  2. useRegExp(r'\[[^\]\[]+\]')matching[smile]Etc., replace with<img src=003_ Smile. PNG width = 22.400000 height = 22.400000 / >
  3. Take the last htmlstring and usehtml | Dart PackageTo parse HTML and generate HTML node tree
  4. Recursive HTML node tree

    1. Text labels are mapped to textspan
    2. Image tags are mapped to fdimagespan; After the flutter is upgraded, it is replaced with widgetspan, and its child is set to image widget
    3. The link label is mapped to textspan, and the corresponding gesture of gesturerecognizer is defined

In the process, the Emoji placeholder is transformed into HTML element, and then the HTML string is processed uniformly. Then the HTML string is unified into rich text. The design is divided into two layers: data analysis layer and rendering layer.

A flutter rich text scheme with easy migration and high compatibility

As shown in the figure above, with the original flutter mixed text support, we can imitate it in the lower version. The lower version of richtext inherits from the leafrenderobjectwidget. We make richtext and other widgets into a new multichildrenderobjectwidget, render the text normally through the placeholder, and then get the position of the placeholder and set the position of the corresponding widget.

How to maintain the business party’s non perception in the process of flutter SDK upgrade? Let’s look at the picture below

A flutter rich text scheme with easy migration and high compatibility

The comparison shows that in the textspan tree, our custom fdimagespan inherited from textspan can actually directly correspond to the native widgetspan. Here, we can modify it directly during the process of mapping HTML node tree to textspan tree. In fdrichtext build, we can directly return to the system richtext. Such a change, for the user can achieve no perception.


A flutter rich text scheme with easy migration and high compatibility

The picture above is the most simple and common system message. In order to highlight the security warning, more red fonts are used. The three rich texts defined in the module can be customized.

A flutter rich text scheme with easy migration and high compatibility

The picture above is rich text involving interaction. The buyer can click the blue word “deliver goods there”. Then the buyer will automatically send “deliver goods there” to the seller, and the seller will automatically reply to the buyer according to the preset question. Clicking will trigger the user-defined protocol link in the HTML string, and the client will trigger the OpenURL operation to realize the interaction.

A flutter rich text scheme with easy migration and high compatibility

This is the rich text that ordinary users can edit and send, rich free fish custom Emoji, interspersed in the text, not only increases the fun of chat, but also enhances the user’s expression.


At present, the display part is only a mixture of text and text. The rich text in the new version supports any widget and has higher playability. Therefore, we can expand the HTML tag description, which needs to be explored continuously in the future.

Due to the limited space, the rich text editor is not mentioned above. The user input box in the message also needs to support free fish custom Emoji. The current version of the scheme directly uses the placeholder (such as “[smile]”), and does not display the actual picture. Let’s look back at the HTML protocol. Can we support the new version of textfield? This is not limited to custom Emoji.

We turn to announcements and details:

A flutter rich text scheme with easy migration and high compatibility

In the future, we may support the rich text editing and display of the above release and baby details. Comparing the two detail pages, it is obvious that the use of rich text is more powerful in expression, and the buyer can easily grasp the key information that the seller wants to express.

It can be seen that in the future, after the unification of the basic ability of rich text editing and display, more business benefits can be made.