Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - TextPainter vs Paragraph for drawing book page

Tags:

flutter

dart

I need to display long text, which will occupy several screens/pages. I have to add some features also, so I would like to implement my own text displaying component.

I found two classes that corresponds to this task:

  • TextPainter
    use TextSpan for text
    use paint(canvas, offset) for painting

  • Paragraph
    use "queue" for text and styles for them
    use Canvas.drawParagraph(paragraph, offset) for painting

What is the difference between them and which one to use?!

If the text contains 100 lines and only 10 lines can be placed on a page, then how to draw truncated text on the next pages until nothing left?

like image 573
Serge Breusov Avatar asked Aug 01 '18 18:08

Serge Breusov


People also ask

How do you write a paragraph in Flutter?

Use \n for paragraphs, like this: Text('Hello,\n\nhow are you?')

How do you show paragraph text in Flutter?

RichText is a very useful widget in Flutter, which is used for displaying a paragraph of text on the UI with multiple styles. Inside the widget, we can have different styles by giving it a tree of TextSpan widgets. Each TextSpan can set its own style for overriding the default style.

How do I paint text in Flutter?

To paint in flutter you use the CustomPaint Widget. The CustomPaint Widget takes a CustomPainter object as a parameter. In that class, you have to override the paint method, which gives you a canvas that you can paint on.


1 Answers

tl;dr: imo TextPainter > Paragraph (because of better API).

I created simple example app to compare both TextPainter and Paragraph methods of rendering text on Canvas (of CustomPainter). Both methods are pretty good, both uses different approaches, both have their weird wobbles.

TextPainter

At first I want to mention that TextPainter interface seems to be easier - at least for me. You just need to specify text as TextSpan entry or tree and - what is weird, it isn't default - textDirection. You can also provide options such as maxLines, style and textAlign (and few others). Then you need to use layout to specify how the rendering would be laying (well, maxWidth only). And finally, paint on certain Canvas at specified Offset.

        final TextPainter textPainter = TextPainter(
          text: TextSpan(text: text, style: style),
          textAlign: TextAlign.justify,
          textDirection: TextDirection.ltr
        )
          ..layout(maxWidth: size.width - 12.0 - 12.0);  
        textPainter.paint(canvas, const Offset(12.0, 36.0));

Used TextSpan is quite universal around the Flutter - RichText and other widgets also are using this class. I also must notice that using TextPainter allows you to check height and width of text in pixels (before rendering).

Paragraph

Second: Paragraph. This seems to be more underlying, procedural method. As you can see below, Paragraph method is less cleaner. First you must use ParagraphBuilder (since Paragraph have no constructor). You need to feed it with ParagraphStyle that contains various text styling such as font information, textAlign, maxLines and so on. Then you can use pushStyle, pop and addText to prepare next and next portion of the paragraph. After build you get the Paragraph which you can drawParagraph on your Canvas.

        final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(
          ui.ParagraphStyle(
            fontSize:   style.fontSize,
            fontFamily: style.fontFamily, 
            fontStyle:  style.fontStyle,
            fontWeight: style.fontWeight,
            textAlign: TextAlign.justify,
          )
        )
          ..pushStyle(style.getTextStyle())
          ..addText(text);
        final ui.Paragraph paragraph = paragraphBuilder.build()
          ..layout(ui.ParagraphConstraints(width: size.width - 12.0 - 12.0)); 
        canvas.drawParagraph(paragraph, const Offset(12.0, 36.0));

Be aware, there is two types of TextStyle (Dart UI and Flutter). In line with pushStyle you can see that Flutter Painting library TextStyle got transformed into Dart UI TextStyle. Another weird thing is that you can/need specify few font settings just in the ParagraphBuilder - even though you are going to use pushStyle in the line after. And the layout must be specified with width.

I think I could be better to use in situations like reading file, especially with formatting, since there will be no need to parse the file into TextSpan tree, which could be costly. I suppose it can be also a bit faster than other methods if you are know what you are doing, but I do not have time to dig it that deeply.

Max lines problem

You might want to clip the text when there is too much of it. Both Paragraph and TextPainter exposes maxLines - to set max lines - and didExceedMaxLines - to detect whether the limit was exceeded -, in one way or another. There is also canvas.clipRect and related methods which allows to clip all drawing into selected space.

Performance

There is also simple performance test (on release), which shows that both methods are comparable (in my testing case TextPainter was no more than 2% faster than Paragraph). It might be also measurement error ¯\_(ツ)_/¯.

like image 165
PsychoX Avatar answered Sep 18 '22 05:09

PsychoX