私はとを持ってTextView
いOnTouchListener
ます。私が欲しいのは、私が取得したときにユーザーが指している文字インデックスですMotionEvent
。の基になるフォントメトリックに到達する方法はありますTextView
か?
3 に答える
次のようなことを試しましたか?
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
}
お役に立てれば...
これを行う簡単な直接的な方法はわかりませんが、 TextView.getPaint()の呼び出しを介してTextViewのPaintオブジェクトを使用して何かをまとめることができるはずです。
ペイントオブジェクトを取得すると、Paint.getFontMetrics()を呼び出して、基になるFontMetricesにアクセスできるようになります。また、Paint.measureText()、Paint.getTextBounds()、Paint.getTextWidths()などの他の関数にアクセスして、表示されるテキストの実際のサイズ。
それは一般的には機能しますが、TonyBluesからの回答にいくつか問題がありました。
まず、 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テキストではうまく機能しません。