Android: Comment déterminer l'index de caractère de la position d'un événement tactile à TextView?
-
21-09-2019 - |
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
?
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.