确定在 android textview 中单击了哪个单词 [英] Determining which word is clicked in an android textview

查看:18
本文介绍了确定在 android textview 中单击了哪个单词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我想显示一段文本(可能是很长的文本),并允许用户单击任何单词.那时,我想确定他们点击了哪个词.我还想得到单词出现的整个句子(这很简单,假设我可以确定单词在文本中的位置).

Basically, I want to display a passage of text (potentially, quite a long text), and allow the user to click on any word. At that point, I want to determine which word they clicked on. I also want to get the whole sentence in which the word appears (this is pretty trivial, assuming I can determine which position the word is at within the text).

理想情况下,我只需要监听 onTouch 事件,获取 X 和 Y,然后说类似 textView.wordAt(event.x, event.y)textView.cursorPositionNearest(event.x, event.y),不过好像没那么容易:-)

Ideally, I would just listen for a onTouch event, get the X and Y, and say something like textView.wordAt(event.x, event.y) or textView.cursorPositionNearest(event.x, event.y), but it seems it's not so easy :-)

我目前的最大努力是使用 TextView 并为每个单词创建一个 ClickableSpan.它可以工作,但不是很优雅,我想如果我在较长的文本上使用它会开始消耗内存.

My current best effort involves using a TextView and creating one ClickableSpan per word. It works, but it ain't exactly elegant, and I guess it would start to eat memory if I use it on longer texts.

private final String text = "This is the text";
private TextView textView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_text_view);

    textView = (TextView) findViewById(R.id.text_view);

    SpannableString ss = new SpannableString(text);
    //  create spans for "this", "is", "the" and "text"
    ss.setSpan(new IndexedClickableSpan(0, 4), 0, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    ss.setSpan(new IndexedClickableSpan(5, 7), 5, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    ss.setSpan(new IndexedClickableSpan(8, 11), 8, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    ss.setSpan(new IndexedClickableSpan(12, 16), 12, 16, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

    textView.setText(ss);
}

private final class IndexedClickableSpan extends ClickableSpan {

    int startIndex, endIndex;

    public IndexedClickableSpan(int startIndex, int endIndex) {
        this.startIndex = startIndex;
        this.endIndex = endIndex;
    }

    @Override
    public void onClick(View widget) {
        String word = TextViewActivity.this.text.substring(startIndex, endIndex);
        Toast.makeText(TextViewActivity.this, "You clicked on " + word, Toast.LENGTH_SHORT).show();
    }
}

如果有人有更好的想法,我很想听听.

If anyone has a better idea, I'd love to hear it.

提前致谢,戴夫

不确定我应该如何回答有关 stackoverflow 的问题,但我已经设法从 Android 15 API 中提取了一些代码,并对其稍作修改以完成我需要的操作.感谢 Dheeraj 的建议.

Not sure how i'm really supposed to answer questions on stackoverflow, but I've managed to rip some code out of the Android 15 API and modify it very slightly to do what i needed. Thanks to Dheeraj for the suggestion.

新代码允许我根据触摸事件位置获取插入符号位置,从那里我应该能够获取被触摸的单词,以及它出现的句子.附加代码:

The new code allows me to get a caret position based on a touch event position, from there I should be able to get the word that was touched, and the sentence it appears in. Code attached:

public int getOffsetForPosition(TextView textView, float x, float y) {
    if (textView.getLayout() == null) {
        return -1;
    }
    final int line = getLineAtCoordinate(textView, y);
    final int offset = getOffsetAtCoordinate(textView, line, x);
    return offset;
}

private int getOffsetAtCoordinate(TextView textView2, int line, float x) {
    x = convertToLocalHorizontalCoordinate(textView2, x);
    return textView2.getLayout().getOffsetForHorizontal(line, x);
}

private float convertToLocalHorizontalCoordinate(TextView textView2, float x) {
    x -= textView2.getTotalPaddingLeft();
    // Clamp the position to inside of the view.
    x = Math.max(0.0f, x);
    x = Math.min(textView2.getWidth() - textView2.getTotalPaddingRight() - 1, x);
    x += textView2.getScrollX();
    return x;
}

private int getLineAtCoordinate(TextView textView2, float y) {
    y -= textView2.getTotalPaddingTop();
    // Clamp the position to inside of the view.
    y = Math.max(0.0f, y);
    y = Math.min(textView2.getHeight() - textView2.getTotalPaddingBottom() - 1, y);
    y += textView2.getScrollY();
    return textView2.getLayout().getLineForVertical((int) y);
}

推荐答案

如果你的目标是 API 级别 14+,你可以使用 getOffsetForPosition().

If you're targeting API level 14+, you could use getOffsetForPosition().

对于以前的Android版本,看看你是否可以从Android源中复制这个方法的代码并扩展你自己的TextView.

For previous Android version, see if you can copy the code for this method from Android source and extend your own TextView.

这篇关于确定在 android textview 中单击了哪个单词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆