4

I'm implementing messureText method in this question to separate long text into pages with specified size before rendering in viewpager. I'm doing a while loop with incremental number of characters to get desired text blocks but it seems not to be the best solution. Is there any suggestion to improve the performance for this calculation?. p/s: I refer to the Wattpad app saw it do this very fast but did not know it how?

Community
  • 1
  • 1
Sinh Phan
  • 1,180
  • 3
  • 16
  • 36

2 Answers2

7

StaticLayout or DynamicLayout could do this. Android use (Boring|Static|Dynamic)Layout classes to measure and wrap text, these classes constructor take CharSequence as input param so styled text(contains spans, even ImageSpan) is acceptable. You can calculate the pageWidth and pageHeight according to your View or Screen, and the TextPaint and two lineSpacing param must equals to your target TextView, here is my code:

import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.text.StaticLayout;
import android.text.TextPaint;

import java.util.ArrayList;
import java.util.List;

public class PageSplitter {
    private final int pageWidth;
    private final int pageHeight;
    private final float lineSpacingMultiplier;
    private final float lineSpacingExtra;
    private final List<CharSequence> pages = new ArrayList<CharSequence>();
    private SpannableStringBuilder mSpannableStringBuilder = new SpannableStringBuilder();

    public PageSplitter(int pageWidth, int pageHeight, float lineSpacingMultiplier, float lineSpacingExtra) {
        this.pageWidth = pageWidth;
        this.pageHeight = pageHeight;
        this.lineSpacingMultiplier = lineSpacingMultiplier;
        this.lineSpacingExtra = lineSpacingExtra;
    }

    public void append(CharSequence charSequence) {
        mSpannableStringBuilder.append(charSequence);
    }

    public void split(TextPaint textPaint) {
        StaticLayout staticLayout = new StaticLayout(
                mSpannableStringBuilder,
                textPaint,
                pageWidth,
                Layout.Alignment.ALIGN_NORMAL,
                lineSpacingMultiplier,
                lineSpacingExtra,
                false
        );
        int startLine = 0;
        while(startLine < staticLayout.getLineCount()) {
            int startLineTop = staticLayout.getLineTop(startLine);
            int endLine = staticLayout.getLineForVertical(startLineTop + pageHeight);
            int endLineBottom = staticLayout.getLineBottom(endLine);
            int lastFullyVisibleLine;
            if(endLineBottom > startLineTop + pageHeight)
                lastFullyVisibleLine = endLine - 1;
            else
                lastFullyVisibleLine = endLine;
            int startOffset = staticLayout.getLineStart(startLine);
            int endOffset = staticLayout.getLineEnd(lastFullyVisibleLine);
            pages.add(mSpannableStringBuilder.subSequence(startOffset, endOffset));
            startLine = lastFullyVisibleLine + 1;
        }
    }

    public List<CharSequence> getPages() {
        return pages;
    }
}
Bugs Happen
  • 2,169
  • 4
  • 33
  • 59
Cryse Hillmes
  • 196
  • 1
  • 3
  • tks... it's nice. i used staticlayout – Sinh Phan May 28 '15 at 00:55
  • Hey. Nice solution, seems like it should solve my problem too. But, unfortunately, I can't understand/follow the code flow. Could you please share a piece of implementation, where this class is called? Please share. Manz thanks in advance! – Mark Delphi Jan 11 '21 at 09:48
0

You can use BufferedReader in your code. You can just leave the string in there and pass operate in this reader. Would be more efficient than first creating a String out of it.

Jordi Castilla
  • 26,609
  • 8
  • 70
  • 109
  • tks for help. if using BufferedReader, only to read long texts there. Want to separate this long texts into each pages for inclusion in viewpager I should do? – Sinh Phan May 15 '15 at 00:51