24

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.

John
  • 477
  • 3
  • 8
  • 15
  • Hi. I am working on the same problem. Do you have any solution for this. I need to find out the visible portion of text from the TextView. Can you help me? – Andro Selva Jul 17 '12 at 06:45
  • As far as I know, I don't think there is a way to do this with TextView. – kosa Dec 26 '11 at 15:42

8 Answers8

17

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);
Adil Soomro
  • 37,609
  • 9
  • 103
  • 153
Kim
  • 231
  • 1
  • 2
7

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;
    }
LifeQuestioner
  • 406
  • 5
  • 14
2

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));
        }
    });
Gil SH
  • 3,789
  • 1
  • 27
  • 25
1

I also having about the same problem myself. I needed first visible line from textview currently visible in recyclerview. If you are trying to get currently displayed first line of textview in recyclerview you may use the following code:

  TextView tv = (TextView) recyclerView.getChildAt(0); //gets current visible child view
  // this is for top visible 
  //view or the textview directly
   Rect r1 = new Rect();
   tv.getHitRect(r1);//gets visible rect of textview
   Layout l = tv.getLayout();

   int line = l.getLineForVertical(-1 * r1.top);//first visible line
   int start = l.getLineStart(line);//visible line start
   int end = l.getLineEnd(line);//visible line end

   String displayed = tv.getText().toString().substring(start, end);
Zain Aftab
  • 703
  • 7
  • 21
1

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.

Snowball
  • 11,102
  • 3
  • 34
  • 51
  • thank you for your suggestion, I just tried that, the approximation is good for short passage. The error is too much for long text that i'm going to display.... I'm thinking of getting TextPaint to measure the text and do the calculation if not too computational intensive. – John Dec 26 '11 at 17:54
0

try use getEllipsisStart()

int end = textView.getLayout().getEllipsisStart(0);
user2474486
  • 213
  • 3
  • 8
0

This depends on the use of Ellipsize in the TextView. Try this:

public String getVisibleText(TextView tv) {
    int lastLine = tv.getMaxLines() < 1 || tv.getMaxLines() > tv.getLineCount() ? tv.getLineCount() : tv.getMaxLines();
    if (tv.getEllipsize() != null && tv.getEllipsize().equals(TextUtils.TruncateAt.END)) {
        int ellCount = tv.getLayout().getEllipsisCount(lastLine - 1);
        if (ellCount > 0 && tv.length() > ellCount)
            return tv.getText().toString().substring(0, tv_title.getText().length() - ellCount);
        return tv.getText().toString();
    } else {
        int end = tv.getLayout().getLineEnd(lastLine - 1);
        return tv.getText().toString().substring(0, end);
    }
}

...

textView.post(new Runnable() {
    @Override
    public void run() {
        Log.d(TAG, getVisibleText(textView));
    }
});
Pavel Kataykin
  • 1,527
  • 15
  • 14
0

Assuming you have the scrolled line number, you can use the following to get displayed text:

int start = tv.getLayout().getLineStart(scrolllinenumber);
int end=scrolllinenumber+tv.getLayout().getHeight();
String displayedtext = tv.getText().toString().substring(start, end);
afakan
  • 31
  • 4