【问题标题】:How can I use onTouchListeners on each word in a TextView?如何在 TextView 中的每个单词上使用 onTouchListeners?
【发布时间】:2026-01-17 23:40:01
【问题描述】:

我想将 onTouchListeners 分配给 TextView 中的每个单词。 (不链接到互联网上的东西,而只是为了继续应用程序内的游戏逻辑)。此时我的游戏的一般动作是查看一个 TextView,触摸一个单词,如果它是您赢得的目标单词,否则根据您触摸的单词加载另一个 TextView 并重复。我现在实现这一点的方法是为每个单词使用 ClickableSpans 和 onClicks。

但我更喜欢 onTouchListeners,这样我就可以在 touch_down 上更改单词背景的颜色,并在 touch_up 上执行游戏逻辑,使其看起来更具响应性。我怎样才能做到这一点?

        final TextView defTV = (TextView) findViewById(R.id.defTV);
        text = new SpannableString(rv); // rv is the future clickable TextView text

        ClickableSpan clickableSpan = null;

        String regex = "\\w+";
        Pattern p = Pattern.compile(regex);

        Matcher matcher = p.matcher(text);
        while (matcher.find()) {
            final int begin = matcher.start();
            final int end = matcher.end();
            clickableSpan = new ClickableSpan() {

                public void onClick(View arg0) {

                    String lword = (String) text.subSequence(begin, end).toString();

                    if (lword.equalsIgnoreCase(targetword)) {
                        // WIN
                    } else {
                        // Build new TextView based on lword, start over
                    }

                }

            };

            text.setSpan(clickableSpan, begin, end, 0);

        }

【问题讨论】:

    标签: android textview ontouchlistener spannablestring


    【解决方案1】:

    所以我复制了 ClickableSpan.java 并制作了 TouchableSpan.java:

    import android.text.TextPaint;
    import android.text.style.CharacterStyle;
    import android.text.style.UpdateAppearance;
    import android.view.MotionEvent;
    import android.view.View;
    
    /**
     * If an object of this type is attached to the text of a TextView
     * with a movement method of LinkTouchMovementMethod, the affected spans of
     * text can be selected.  If touched, the {@link #onTouch} method will
     * be called.
     */
    public abstract class TouchableSpan extends CharacterStyle implements UpdateAppearance     {
    
        /**
         * Performs the touch action associated with this span.
         * @return 
         */
        public abstract boolean onTouch(View widget, MotionEvent m);
    
        /**
         * Could make the text underlined or change link color.
         */
        @Override
        public abstract void updateDrawState(TextPaint ds);
    
    }
    

    我将LinkMovementMethod.java 扩展为LinkTouchMovementMethod.java。 onTouchEvent 方法相同,只是将 onClick 的提及改为 onTouch 并添加了一个新行:

    import android.text.Layout;
    import android.text.Selection;
    import android.text.Spannable;
    import android.text.method.LinkMovementMethod;
    import android.view.MotionEvent;
    import android.widget.TextView;
    
    public class LinkTouchMovementMethod extends LinkMovementMethod
    {
    
        @Override
        public boolean onTouchEvent(TextView widget, Spannable buffer,
                                MotionEvent event) {
            int action = event.getAction();
    
            if (action == MotionEvent.ACTION_UP ||
                action == MotionEvent.ACTION_DOWN) {
                int x = (int) event.getX();
                int y = (int) event.getY();
    
                x -= widget.getTotalPaddingLeft();
                y -= widget.getTotalPaddingTop();
    
                x += widget.getScrollX();
                y += widget.getScrollY();
    
                Layout layout = widget.getLayout();
                int line = layout.getLineForVertical(y);
                int off = layout.getOffsetForHorizontal(line, x);
    
                TouchableSpan[] link = buffer.getSpans(off, off, TouchableSpan.class);
    
                if (link.length != 0) {
                    if (action == MotionEvent.ACTION_UP) {
                        link[0].onTouch(widget,event); //////// CHANGED HERE
                    } else if (action == MotionEvent.ACTION_DOWN) {
                        link[0].onTouch(widget,event); //////// ADDED THIS
                        Selection.setSelection(buffer,
                                               buffer.getSpanStart(link[0]),
                                               buffer.getSpanEnd(link[0]));
                    }
    
                    return true;
                } else {
                    Selection.removeSelection(buffer);
                }
            }
    
            return super.onTouchEvent(widget, buffer, event);
        }
    
    }
    

    并在您的代码中适当地设置 MovementMethod:

    TextView tv = (TextView) findViewById(R.id.tv);
    tv.setMovementMethod(new LinkTouchMovementMethod());
    

    现在显示文本:

    touchableSpan = new TouchableSpan() {
    
        public boolean onTouch(View widget, MotionEvent m) {
    
            ...
    
        }
    
        public void updateDrawState(TextPaint ds) {
            ds.setUnderlineText(false);
            ds.setAntiAlias(true);
        }
    
    };
    
    String rv = "Text to span";
    
    text = new SpannableString(rv);
    
    text.setSpan(touchableSpan, begin, end, 0);
    
    tv.setText(text, BufferType.SPANNABLE);
    

    【讨论】:

    • 在 Activity 中将最后的代码和平放在哪里??
    • @elliptic1,感谢你漂亮的代码,但它不适用于android M,请查看问题,我在*上提出了一个问题,其链接如下,*.com/questions/34737514/…跨度>
    • @elliptic1,我通过将 textview 转换为按钮解决了我的问题,但请帮助我,因为我不知道为什么它现在可以在 android M 上使用 textview。
    • @VikramSingh 我在 M 上对其进行了测试,对我来说效果很好。
    • @sosite,我不知道出了什么问题,但是当我将其更改为按钮时,它对我来说很好
    最近更新 更多