ClickableSpan奇怪的行为:单击空格时调用的onClick()

时间:2012-02-14 09:18:42

标签: android html textview

我有TextView ClickableSpan,其中layout_height和layout_width都是wrap_content。

TextView中的文字不太长时,它可以正常工作。 当文本足够长以使它占用2行时,它也可以正常工作但有一些奇怪的行为。

这是当我点击第二行的空白区域(不是填充文本但是TextView的一部分)时,会调用ClickableSpan onClick()回调。

我没想到这一点,因为我只点击空白区域而不是单击跨区文本。 虽然它没有太大影响,但我想知道背后是什么。

我使用以下代码设置ClickableSpan

TextView tv = (TextView) findViewById(R.id.text);
tv.setText("TEXT TEXT TEXT TEXT");
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(tv.getText());
ssb.setSpan(new TestClickableSpan(), ssb.length()-5, ssb.length(), 0);
tv.setText(ssb);
tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setOnTouchListener(new TextViewOnTouchListener());

TextViewOnTouchListener:

class TextViewOnTouchListener implements OnTouchListener{

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.d("TextView", "onTouch");
            return false;
        }       
}

TestClickableSpan:

class TestClickableSpan extends ClickableSpan{

        @Override
        public void onClick(View arg0) {
            Log.d("ClickableSpan", "Confirm OnClick: "+arg0.toString());
        }       
    }

4 个答案:

答案 0 :(得分:13)

我设法通过扩展LinkMovementMethod来解决它,并检查是否触摸事件 offset等于或大于文本长度:

public class MovementMethod 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);

            if (off >= widget.getText().length()) {
               // Return true so click won't be triggered in the leftover empty space
                return true;
            }
        }

        return super.onTouchEvent(widget, buffer, event);
    }
}

答案 1 :(得分:1)

dor506的答案对只有一行的EditTexts非常有用。但是,当用户键入多行时,该解决方案仅适用于最后一行。也就是说,底行中的ClickableSpans可以正常运行,但其他所有行中都可以通过空格单击。

我通过以下方法解决了这个问题:

if (off >= widget.getText().length()) {
    // Return true so click won't be triggered in the leftover empty space
    return true;
}

收件人:

if (off >= layout.getLineVisibleEnd(line)) {
    // Return true so click won't be triggered in the leftover empty space
    return true;
}

(很抱歉将其作为单独的答案发布-我没有足够的声誉来添加评论,但我认为这可能值得记录!)

答案 2 :(得分:1)

感谢@ dor506的回答,但不适用于重力center,我做了一些修改。

@Override
        public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
            int action = event.getAction();

            if (action == MotionEvent.ACTION_UP) {
                int x = (int) event.getX();
                int y = (int) event.getY();

                y -= widget.getTotalPaddingTop();
                y += widget.getScrollY();

                Layout layout = widget.getLayout();
                int line = layout.getLineForVertical(y);
                float lineLeft = layout.getLineLeft(line);
                float lineRight = layout.getLineRight(line);

                if (x > lineRight || (x >= 0 && x < lineLeft)) {
                    return true;
                }
            }

            return super.onTouchEvent(widget, buffer, event);
        }

答案 3 :(得分:0)

dor506的答案对我不起作用,因此我寻找其他解决方案并找到了这个存储库: https://github.com/saket/Better-Link-Movement-Method

将其添加到您的项目后,按以下方式使用它:

textView.setMovementMethod(BetterLinkMovementMethod.newInstance());

应该可以解决问题。