Android: Comment déterminer l'index de caractère de la position d'un événement tactile à TextView?

StackOverflow https://stackoverflow.com/questions/2302867

Question

J'ai un TextView avec un OnTouchListener. Ce que je veux est l'index de caractère que l'utilisateur pointe quand je reçois le MotionEvent. Est-il possible d'obtenir des mesures de police sous-jacentes de la TextView?

Était-ce utile?

La solution

Je ne suis pas au courant d'une façon simple directe de le faire, mais vous devriez être en mesure de mettre quelque chose ensemble en utilisant le Peinture objet de la TextView via un appel à TextView.getPaint ()

Une fois que vous avez l'objet de la peinture, vous aurez accès aux sous-jacents FontMetrices via un appel à Paint.getFontMetrics () et avoir accès à d'autres fonctions telles que Paint.getTextBounds Paint.measureText () (), et Paint.getTextWidths () pour accéder à la taille réelle du texte affiché.

Autres conseils

Avez-vous essayé quelque chose comme ceci:

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
}

Hope this helps ...

Bien qu'il fonctionne généralement j'ai eu quelques problèmes avec la réponse de Tony Blues.

Tout d'abord getOffsetForHorizontal rendement un même décalage si la coordonnée x est bien au-delà du dernier caractère de la ligne.

En second lieu le caractère de retour décalé appartient parfois au caractère suivant, pas le caractère directement sous le pointeur. Apparemment, la méthode renvoie le décalage de la position du curseur le plus proche. Cela peut être à gauche ou à droite du caractère en fonction de ce qui est plus proche par.

Ma solution utilise getPrimaryHorizontal au lieu de déterminer la position du curseur d'un certain décalage et utilise la recherche binaire pour trouver le décalage en dessous des x du pointeur de coordonnées.

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

Edit:. Cette version mise à jour fonctionne mieux avec des sauts de ligne non naturelle, quand un long mot ne correspond pas à une ligne et se diviser quelque part au milieu

Mises en garde: Dans les textes césure, en cliquant sur le trait d'union à la fin d'une ligne renvoie l'index du caractère à côté de lui. De plus, cette méthode ne fonctionne pas bien avec les textes RTL.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top