2

I have a multi-line body of text which I want to split across screens. I am using the Text widget with overflow property like this:

Text(
    body,
    style: Theme.of(context).textTheme.bodyText2,
    maxLines: 8,
    overflow: TextOverflow.ellipsis,
  );

Now, on the next page, I want to start the text from the word where the previous page got truncated. For example, for the body 'Hello, nice to meet you all. Hope you have a good day!', this is what it would look like:

On Page 1:

Hello, nice to meet you all. Hope...

On Page 2:

...you have a good day!

Now, I am trying to find a way for the Text widget to tell me where it truncated the text on Page 1. Anybody got any suggestions on how to go about it?

aceBox
  • 711
  • 2
  • 13
  • 30
  • Could you check it https://stackoverflow.com/a/53939279/13109852 – Salih Can Feb 17 '22 at 21:18
  • @SalihCan thanks for the link; however, this only tells on how to use an alternative text in case there is an overflow...not, how to split the text into pages. Can you elaborate on how this may be helpful? – aceBox Feb 18 '22 at 13:42

1 Answers1

1

I found the answer to what I was looking for. It's a clever way of using TextPainter's computeLineMetrics method. Original source from here: SplittedText

Specifically, the below code is helpful:

import 'dart:ui';
import 'package:flutter/cupertino.dart';

abstract class SplittedText {
  List<String> getSplittedText(Size pageSize, TextStyle textStyle, String text);
}

class SplittedTextImpl extends SplittedText {
  @override
  List<String> getSplittedText(
      Size pageSize, TextStyle textStyle, String text) {
    final List<String> _pageTexts = [];
    final textSpan = TextSpan(text: text, style: textStyle);
    final textPainter = TextPainter(
      text: textSpan,
      textDirection: TextDirection.ltr,
    );
    textPainter.layout(
      minWidth: 0,
      maxWidth: pageSize.width,
    );

    // https://medium.com/swlh/flutter-line-metrics-fd98ab180a64
    List<LineMetrics> lines = textPainter.computeLineMetrics();
    double currentPageBottom = pageSize.height;
    int currentPageStartIndex = 0;
    int currentPageEndIndex = 0;

    for (int i = 0; i < lines.length; i++) {
      final line = lines[i];

      final left = line.left;
      final top = line.baseline - line.ascent;
      final bottom = line.baseline + line.descent;

      // Current line overflow page
      if (currentPageBottom < bottom) {
        // https://stackoverflow.com/questions/56943994/how-to-get-the-raw-text-from-a-flutter-textbox/56943995#56943995
        currentPageEndIndex =
            textPainter.getPositionForOffset(Offset(left, top)).offset;
        final pageText =
            text.substring(currentPageStartIndex, currentPageEndIndex) ?? "";
        _pageTexts.add(pageText);

        currentPageStartIndex = currentPageEndIndex;
        currentPageBottom = top + pageSize.height;
      }
    }

    final lastPageText = text.substring(currentPageStartIndex) ?? "";
    _pageTexts.add(lastPageText);
    return _pageTexts;
  }
}
aceBox
  • 711
  • 2
  • 13
  • 30