Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Separate long text into pages for viewpager

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?

like image 490
Phan Sinh Avatar asked Mar 17 '23 01:03

Phan Sinh


1 Answers

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;
    }
}
like image 147
Cryse Hillmes Avatar answered Mar 19 '23 05:03

Cryse Hillmes