获取TextView中当前可见的文本

24

我有一个包含在ScrollView中的长文本段落。有没有办法找到当前可见的文本?

我能够找到TextView中的行数、行高以及ScrollView中的scrollx和scrolly,但无法找到与当前显示的文本相对应的内容。请帮忙!谢谢。


据我所知,我认为TextView没有这样做的方法。 - kosa
嗨,我正在解决同样的问题。你有解决方案吗?我需要找出TextView中可见的文本部分。你能帮我吗? - Andro Selva
8个回答

17

这很简单:

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

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

7

在这里,先获取第一行的显示行号。然后获取第二行的显示行号。接着获取文本并计算单词数。

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;
    }

这个非常好用(getLineStart + getLineForVertical)。 - Nimitz14

2

如果 android:singleLine="true",可以使用 textView.getLayout().getEllipsisStart(0)。

如果设置了 android:maxLines,则可以使用以下解决方案:

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;
}

请记住:这个方法需要在视图已经加载的情况下使用。 用法:
textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            Log.i("test" ,"VisibleText="+getVisibleText(textView));
        }
    });

1

你声称你知道 scrollY,即当前滚动的像素数。你还知道你正在考虑的窗口的高度(以像素为单位),所以将其称为 scrollViewHeight。然后

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);

这只是一个近似值,所以请把它作为最后的选择。


谢谢您的建议,我刚刚尝试了一下,对于短文来说近似值还不错。但是对于我要显示的长文本来说误差太大了... 我正在考虑使用TextPaint来测量文本并进行计算,如果不会过于计算密集的话。 - John

1

我自己也遇到了类似的问题。我需要从当前在recyclerview中可见的textview获取第一行。如果你正试图获取recyclerview中textview当前显示的第一行,你可以使用以下代码:

  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);

0
这取决于TextView中使用Ellipsize的方式。试试这个:
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));
    }
});

0

尝试使用getEllipsisStart()

int end = textView.getLayout().getEllipsisStart(0);

0
假设您已经有了滚动行号,您可以使用以下内容来获取显示的文本:
int start = tv.getLayout().getLineStart(scrolllinenumber);
int end=scrolllinenumber+tv.getLayout().getHeight();
String displayedtext = tv.getText().toString().substring(start, end);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接