Android ClickableSpan 未调用 onClick

问题描述 投票:0回答:5

我正在创建一个 ClickableSpan,它可以正确显示 正确的文字加下划线。但是,点击次数并未记录。 你知道我做错了什么吗???

谢谢,维克多

这是代码片段:

view.setText("This is a test");
ClickableSpan span = new ClickableSpan() {
    @Override
    public void onClick(View widget) {
        log("Clicked");
    }
};
view.getText().setSpan(span, 0, view.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
android textview
5个回答
544
投票

您是否尝试过在包含跨度的 TextView 上设置 MovementMethod?您需要这样做才能使点击起作用......

tv.setMovementMethod(LinkMovementMethod.getInstance());

14
投票

Kotlin 实用函数:

fun setClickable(textView: TextView, subString: String, handler: () -> Unit, drawUnderline: Boolean = false) {
    val text = textView.text
    val start = text.indexOf(subString)
    val end = start + subString.length

    val span = SpannableString(text)
    span.setSpan(ClickHandler(handler, drawUnderline), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

    textView.linksClickable = true
    textView.isClickable = true
    textView.movementMethod = LinkMovementMethod.getInstance()

    textView.text = span
}

class ClickHandler(
        private val handler: () -> Unit,
        private val drawUnderline: Boolean
) : ClickableSpan() {
    override fun onClick(widget: View?) {
        handler()
    }

    override fun updateDrawState(ds: TextPaint?) {
        if (drawUnderline) {
            super.updateDrawState(ds)
        } else {
            ds?.isUnderlineText = false
        }
    }
}

用途:

Utils.setClickable(textView, subString, {handleClick()})

9
投票

经过一番尝试和错误后,设置

tv.setMovementMethod(LinkMovementMethod.getInstance());
的顺序确实很重要。

这是我的完整代码

String stringTerms = getString(R.string.sign_up_terms);
Spannable spannable = new SpannableString(stringTerms);
int indexTermsStart = stringTerms.indexOf("Terms");
int indexTermsEnd = indexTermsStart + 18;
spannable.setSpan(new UnderlineSpan(), indexTermsStart, indexTermsEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new ForegroundColorSpan(getColor(R.color.theme)), indexTermsStart, indexTermsEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new ClickableSpan() {
    @Override
    public void onClick(View widget) {
        Log.d(TAG, "TODO onClick.. Terms and Condition");
    }
}, indexTermsStart, indexTermsEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

int indexPolicyStart = stringTerms.indexOf("Privacy");
int indexPolicyEnd = indexPolicyStart + 14;
spannable.setSpan(new UnderlineSpan(), indexPolicyStart, indexPolicyEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new ForegroundColorSpan(getColor(R.color.theme)), indexPolicyStart, indexPolicyEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new ClickableSpan() {
    @Override
    public void onClick(View widget) {
        Log.d(TAG, "TODO onClick.. Privacy Policy");
    }
}, indexPolicyStart, indexPolicyEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

TextView textViewTerms = (TextView) findViewById(R.id.sign_up_terms_text);
textViewTerms.setText(spannable);
textViewTerms.setClickable(true);
textViewTerms.setMovementMethod(LinkMovementMethod.getInstance());

6
投票

Kotlin 中的直接方法

  val  textHeadingSpannable = SpannableString(resources.getString(R.string.travel_agent))


           val clickSpan = object : ClickableSpan(){
               override fun onClick(widget: View) {

                // Handel your click
               }
           }
            textHeadingSpannable.setSpan(clickSpan,104,136,Spannable.SPAN_INCLUSIVE_EXCLUSIVE)

            tv_contact_us_inquire_travel_agent.movementMethod = LinkMovementMethod.getInstance()
            tv_contact_us_inquire_travel_agent.text = textHeadingSpannable

0
投票

好吧,我对 LinkMovement 存在某些问题,例如点击是在

MotionEvent.ActionDown
本身上触发的,这并不是真正的点击,所以我结束了自定义
MovementMethod

class CustomMovementMethod implements MovementMethod {
    private final int normalColor, selectedColor;
    private boolean didClickedOnActionDown = false;

    private CustomMovementMethod(int normalColor, int selectedColor) {
        this.normalColor = normalColor;
        this.selectedColor = selectedColor;
    }

    @Override
    public void initialize(TextView widget, Spannable text) {

    }

    @Override
    public boolean onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event) {
        return false;
    }

    @Override
    public boolean onKeyUp(TextView widget, Spannable text, int keyCode, KeyEvent event) {
        return false;
    }

    @Override
    public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) {
        return false;
    }

    @Override
    public void onTakeFocus(TextView widget, Spannable text, int direction) {

    }

    @Override
    public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) {
        return false;
    }

    @Override
    public boolean onTouchEvent(TextView widget, Spannable text, 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();

            Layout layout = widget.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);

            ClickableSpan[] links = text.getSpans(off, off, ClickableSpan.class);

            if (links.length > 0) {
                if (action == MotionEvent.ACTION_UP) {
                    if (didClickedOnActionDown) {
                        widget.setLinkTextColor(normalColor);
                        links[0].onClick(widget);
                    }
                }
                else {
                    widget.setLinkTextColor(selectedColor);
                    didClickedOnActionDown = true;
                }
            } else if (didClickedOnActionDown) {
                widget.setLinkTextColor(normalColor);
                didClickedOnActionDown = false;
            }
        }
        return false;
    }

    @Override
    public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event) {
        return false;
    }

    @Override
    public boolean canSelectArbitrarily() {
        return false;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.