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

Epa*_*aga 8 android textview ontouchlistener fontmetrics

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

Ton*_*ues 25

你尝试过这样的事情:

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
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助...


snc*_*tln 5

我不知道一个简单的直接方法,但你应该能够通过调用TextView.getPaint()使用TextView 的Paint对象将一些东西放在一起

获得paint对象后,您可以通过调用Paint.getFontMetrics()访问底层FontMetrices,并可以访问其他函数,如Paint.measureText()Paint.getTextBounds()和Paint.getTextWidths()以访问显示文本的实际大小.


dev*_*ole 5

虽然它通常有效,但我对托尼布鲁斯的答案有一些疑问。

首先,即使 x 坐标远远超出该行的最后一个字符,getOffsetForHorizo​​ntal也会返回一个偏移量。

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

我的解决方案使用getPrimaryHorizo​​ntal来确定某个偏移量的光标位置,并使用二分搜索来查找指针 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;
}
Run Code Online (Sandbox Code Playgroud)

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

注意事项:在带连字符的文本中,单击行末尾的连字符将返回其旁边的字符的索引。此外,此方法不适用于 RTL 文本。