Android: Как определить индекс символа позиции сенсорного события в TextView? - PullRequest
8 голосов
/ 20 февраля 2010

У меня есть TextView с OnTouchListener. То, что я хочу, - это индекс символов, на который указывает пользователь, когда я получаю MotionEvent. Есть ли способ добраться до основных метрик шрифта TextView?

Ответы [ 3 ]

24 голосов
/ 28 апреля 2011

Вы пробовали что-то вроде этого:

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
}

Надеюсь, это поможет ...

5 голосов
/ 20 февраля 2010

Мне неизвестен простой прямой способ сделать это, но вы должны быть в состоянии собрать что-то вместе, используя объект Paint TextView с помощью вызова TextView.getPaint ()

Получив объект рисования, вы получите доступ к базовым элементам FontMetrices через вызов Paint.getFontMetrics () и получите доступ к другим функциям, таким как Paint.measureText () Paint.getTextBounds () и Paint.getTextWidths () для доступа к фактическому размеру отображаемого текста.

1 голос
/ 06 апреля 2018

Хотя это обычно работает, у меня было несколько проблем с ответом Тони Блюза.

Во-первых, getOffsetForHorizont * возвращает смещение, даже если координата x находится далеко за последним символом строки.

Во-вторых, возвращаемое смещение символа иногда принадлежит следующему символу, а не символу непосредственно под указателем. Видимо, метод возвращает смещение ближайшей позиции курсора. Это может быть слева или справа от персонажа в зависимости от того, что ближе.

Мое решение вместо этого использует getPrimaryHor horizontal , чтобы определить положение курсора определенного смещения, и использует двоичный поиск, чтобы найти смещение под координатой 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.

...