Android:如何在TextView中确定触摸事件位置的字符索引?

时间:2010-02-20 16:44:18

标签: android textview fontmetrics ontouchlistener

我有TextView OnTouchListener。我想要的是当我得到MotionEvent时用户指向的字符索引。有没有办法获得TextView的基础字体指标?

3 个答案:

答案 0 :(得分:23)

你有没有试过这样的事情:

Layout layout = this.getLayout();
if (layout != null)
{
    int line = layout.getLineForVertical(y);
    int offset = layout.getOffsetForHorizontal(line, x);

    // At this point, "offset" should be what you want - the character index
}

希望这会有所帮助......

答案 1 :(得分:5)

我不知道一个简单的直接方法,但您应该能够通过调用Paint

使用TextView的TextView.getPaint()对象将某些内容组合在一起

拥有paint对象后,您可以通过调用Paint.getFontMetrics()访问基础FontMetrices,并可以访问其他函数,如Paint.measureText()Paint.getTextBounds()和Paint.getTextWidths()用于访问显示文本的实际大小。

答案 2 :(得分:1)

虽然它通常有效但我对Tony Blues的回答有些问题。

首先getOffsetForHorizontal返回一个偏移,即使x坐标超出了该行的最后一个字符。

其次,返回的字符偏移有时属于下一个字符,而不是指针下面的字符。显然,该方法返回最近光标位置的偏移量。这可能是角色的左侧或右侧,取决于附近的内容。

我的解决方案使用getPrimaryHorizontal来确定某个偏移的光标位置,并使用二进制搜索来找到指针x坐标下方的偏移量。

public static int getCharacterOffset(TextView textView, int x, int y) {
    x += textView.getScrollX() - textView.getTotalPaddingLeft();
    y += textView.getScrollY() - textView.getTotalPaddingTop();

    final Layout layout = textView.getLayout();

    final int lineCount = layout.getLineCount();
    if (lineCount == 0 || y < layout.getLineTop(0) || y >= layout.getLineBottom(lineCount - 1))
        return -1;

    final int line = layout.getLineForVertical(y);
    if (x < layout.getLineLeft(line) || x >= layout.getLineRight(line))
        return -1;

    int start = layout.getLineStart(line);
    int end = layout.getLineEnd(line);

    while (end > start + 1) {
        int middle = start + (end - start) / 2;

        if (x >= layout.getPrimaryHorizontal(middle)) {
            start = middle;
        }
        else {
            end = middle;
        }
    }

    return start;
}

编辑:当一个长单词不适合一行并在中间某处分割时,这个更新版本可以更好地处理不自然的换行符。

警告:在带连字符的文本中,单击行尾的连字符将返回其旁边字符的索引。此方法也不适用于RTL文本。