代码之家  ›  专栏  ›  技术社区  ›  Epaga Alex Reynolds

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

  •  7
  • Epaga Alex Reynolds  · 技术社区  · 15 年前

    我有一个 TextView 用一个 OnTouchListener . 我想要的是当我得到 MotionEvent .是否有任何方法可以获得 文本框 是吗?

    3 回复  |  直到 6 年前
        1
  •  5
  •   snctln    15 年前

    我不知道一个简单直接的方法来做这件事,但是你应该能够用 Paint 通过调用 TextView.getPaint()

    一旦拥有了paint对象,您就可以通过调用paint.getfontMetrics()访问基础的fontMetrics,并可以访问paint.measureText()paint.gettextBounds()和paint.gettextWidths()等其他函数来访问显示文本的实际大小。

        2
  •  23
  •   Tony Blues    14 年前

    您是否尝试过类似的操作:

    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
    }
    

    希望这有帮助…

        3
  •  1
  •   devconsole    6 年前

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

    首先 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文本中也不能很好地工作。

    推荐文章