Flutter - TextPainter vs Paragraph for drawing book page

跟風遠走 提交于 2021-02-06 02:57:10

问题


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?


回答1:


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 ¯\_(ツ)_/¯.



来源:https://stackoverflow.com/questions/51640388/flutter-textpainter-vs-paragraph-for-drawing-book-page

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!