Get current visible text in textview

I have a long passage in a TextView which is wrapped around by ScrollView. Is there any way to find the current visible text?

I can find the number of lines, line height in textview and also scrollx and scrolly from scrollview, but find the linkage to the current displayed text. Please help! Thanks.


It is simple to do this:

int start = textView.getLayout().getLineStart(0);
int end = textView.getLayout().getLineEnd(textView.getLineCount() - 1);

String displayed = textView.getText().toString().substring(start, end);

Here. Get the line number of the first displayed line. Then get the line number of the second displayed line. Then get the text and count the number of words.

private int getNumberOfWordsDisplayed() {
        int start = textView.getLayout().getLineStart(getFirstLineIndex());
        int end = textView.getLayout().getLineEnd(getLastLineIndex());
        return textView.getText().toString().substring(start, end).split(" ").length;
    }

    /**
     * Gets the first line that is visible on the screen.
     *
     * @return
     */
    public int getFirstLineIndex() {
        int scrollY = scrollView.getScrollY();
        Layout layout = textView.getLayout();
        if (layout != null) {
            return layout.getLineForVertical(scrollY);
        }
        Log.d(TAG, "Layout is null: ");
        return -1;
    }

    /**
     * Gets the last visible line number on the screen.
     * @return last line that is visible on the screen.
     */
    public int getLastLineIndex() {
        int height = scrollView.getHeight();
        int scrollY = scrollView.getScrollY();
        Layout layout = textView.getLayout();
        if (layout != null) {
            return layout.getLineForVertical(scrollY + height);
        }
        return -1;
    }

Using textView.getLayout().getEllipsisStart(0) only works if android:singleLine="true"

Here is a solution that will work if android:maxLines is set:

public static String getVisibleText(TextView textView) {
    // test that we have a textview and it has text
    if (textView==null || TextUtils.isEmpty(textView.getText())) return null;
    Layout l = textView.getLayout();
    if (l!=null) {
        // find the last visible position
        int end = l.getLineEnd(textView.getMaxLines()-1);
        // get only the text after that position
        return textView.getText().toString().substring(0,end);
    }

    return null;
}

Remember: this works after the view is already loaded.

Usage:

textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            Log.i("test" ,"VisibleText="+getVisibleText(textView));
        }
    });

You claim that you know scrollY, the current number of pixels scrolled. You also know the height of the window you're considering in pixels, so call that scrollViewHeight. Then

int scrollY; // This is your current scroll position in pixels.
int scrollViewHeight; // This is the height of your scrolling window.
TextView textView; // This is the TextView we're considering.

String text = (String) textView.getText();
int charsPerLine = text.length() / textView.getLineCount();
int lineHeight = textView.getLineHeight();

int startLine = scrollY / lineHeight;
int endLine = startLine + scrollViewHeight/lineHeight + 1;

int startChar = charsPerLine * startLine;
int endChar = charsPerLine * (endLine+1) + 1;
String approxVisibleString = text.substring(startChar, endChar);

It's an approximation, so use it as a last resort.