ClickableSpan和View.onClick()事件冲突解决

项目需求是可以实现文章的点开查看全文和收起功能这里用到了

SpannableStringBuilder进行拼接,对文章行数以及字数进行相关的处理,然后进行点击事件的处理

结果最后出现了问题:在同一段文字中,点击可点击文字部分时,所有的文字也会响应,也就是span响应的同时,onclick也响应了

第一时间想到的就是怎么拦截它

下面奉上自定义的这个View

public class CollapsedTextView extends androidx.appcompat.widget.AppCompatTextView {
    /**
     * 收起状态下的最大行数
     */
    private int maxLine = 1;
    /**
     * 截取后,文本末尾的字符串
     */
    private static final String ELLIPSE = "...";
    /**
     * 默认全文的Text
     */
    private static final String EXPANDEDTEXT = "展开全文";


    /**
     * 默认收起的text
     */
    private static final String COLLAPSEDTEXT = "收起";
    /**
     * 所有行数
     */
    private int allLines = 1;
    /**
     * 是否是收起状态,默认收起
     */
    private boolean collapsed = true;
    /**
     * 真实的text
     */
    private String text;
    /**
     * 收起时实际显示的text
     */
    private CharSequence collapsedCs;
    private SpannableStringBuilder downBT;
    private SpannableStringBuilder upBT;


    public CollapsedTextView(Context context) {
        super(context);
        initView(context, null);
    }

    public CollapsedTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView(context, attrs);
    }

    public CollapsedTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs);
    }

    private void initView(Context context, AttributeSet attrs) {
        downBT = new SpannableStringBuilder("展开全文");
        Drawable dDown = getResources().getDrawable(R.drawable.ic_launcher);//subs_descibe_up
        dDown.setBounds(0, 0, dDown.getIntrinsicWidth() , dDown.getIntrinsicHeight());
        //创建ImageSpan
        ImageSpan downSpan = new ImageSpan(dDown, ImageSpan.ALIGN_BASELINE);
        //用ImageSpan替换文本
        downBT.setSpan(EXPANDEDTEXT, 0, downBT.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
//        downBT.setSpan(downSpan, 0, downBT.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//图标

        upBT = new SpannableStringBuilder(" 收起");
        Drawable dUp = getResources().getDrawable(R.drawable.ic_launcher);//subs_descibe_down
        dUp.setBounds(0, 0, dUp.getIntrinsicWidth(), dUp.getIntrinsicHeight());
        //创建ImageSpan
        ImageSpan upSpan = new ImageSpan(dUp, ImageSpan.ALIGN_BASELINE);
        //用ImageSpan替换文本
        upBT.setSpan(COLLAPSEDTEXT, 0, upBT.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
//        upBT.setSpan(upSpan, 0, upBT.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//图标
    }

    public void setShowText(String text) {
        this.text = text;
        if (allLines > 0) {
            getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    ViewTreeObserver obs = getViewTreeObserver();
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                        obs.removeOnGlobalLayoutListener(this);
                    } else {
                        obs.removeGlobalOnLayoutListener(this);
                    }
                    TextPaint paint = getPaint();
                    float measureText = paint.measureText(text);
                    int showWidth = getWidth() - getPaddingLeft() - getPaddingRight();
                    int lines = (int) (measureText / showWidth);
                    if (measureText % showWidth != 0) {
                        lines++;
                    }
                    allLines = (int) (paint.measureText(text + downBT) / showWidth);
                    if (lines > maxLine) {
                        int expect = text.length() / lines;
                        int end = 0;
                        int lastLineEnd = 0;
                        int expandedTextWidth = (int) paint.measureText(ELLIPSE + downBT);
                        //计算每行显示文本数
                        for (int i = 1; i <= maxLine; i++) {
                            int tempWidth = 0;
                            if (i == maxLine) {

                                tempWidth = expandedTextWidth;
                            }
                            end += expect;
                            if (end > text.length()) {
                                end = text.length();
                            }
                            if (paint.measureText(text, lastLineEnd, end) > showWidth - tempWidth) {
                                //预期的第一行超过了实际显示的宽度
                                end--;
                                while (paint.measureText(text, lastLineEnd, end) > showWidth - tempWidth) {
                                    end--;
                                }
                            } else {
                                end++;
                                while (paint.measureText(text, lastLineEnd, end) < showWidth - tempWidth) {
                                    end++;
                                }
                                end--;
                            }
                            lastLineEnd = end;

                        }
                        setMovementMethod(MyLinkedMovementMethod.getInstance());
                        SpannableStringBuilder s = new SpannableStringBuilder(text, 0, end)
                                .append(ELLIPSE);
                        collapsedCs = addClickableSpan(s, downBT);
                        setText(collapsedCs);
                        append(downBT);
                    } else {
                        setText(text);
                    }

                }
            });
        }
    }


    private static class MyLinkedMovementMethod extends  LinkMovementMethod{
        private static MyLinkedMovementMethod sInstance;
        public static MyLinkedMovementMethod getInstance() {
            if (sInstance == null)
                sInstance = new MyLinkedMovementMethod();
            return sInstance;
        }
        @Override
        public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
            // 因为TextView没有点击事件,所以点击TextView的非富文本时,super.onTouchEvent()返回false;
            // 此时可以让TextView的父容器执行点击事件;
            boolean isConsume =  super.onTouchEvent(widget, buffer, event);
            if (!isConsume && event.getAction() == MotionEvent.ACTION_UP) {
                ViewParent parent = widget.getParent();
                if (parent instanceof ViewGroup) {
                    // 获取被点击控件的父容器,让父容器执行点击;
                    ((ViewGroup) parent).performClick();
                }
            }
            return isConsume;
        }
    }

    private CharSequence addClickableSpan(SpannableStringBuilder s, SpannableStringBuilder collapsedText) {
        collapsedText.setSpan(new ClickableSpan() {//这里用可以点击的部分进行setspan
            @Override
            public void onClick(@NonNull View widget) {
                if (collapsed) {
                    SpannableStringBuilder s = new SpannableStringBuilder(text);
                    setText(addClickableSpan(s, upBT));
                    append(upBT);
                } else {
                    setText(collapsedCs);
                    append(downBT);
                }
                collapsed = !collapsed;
            }
            @Override
            public void updateDrawState(TextPaint ds) {
                super.updateDrawState(ds);
                ds.setAntiAlias(true);
                ds.setUnderlineText(false);
            }

        },0, collapsedText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        return s;
    }
}

 

借鉴文章:https://blog.csdn.net/Love667767/article/details/82903992

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

csdn_zxw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值