类似微信和微博的TextView

321 阅读2分钟

这样一句话,Glad to see you @xxx, we will cooperate with you. 其中@xxx最初的颜色和其它不同,按下@xxx会变成另一个颜色,抬起恢复,并且响应点击事件,当然我们还可以对TextView设置包括背景色等一系列操作

获取down和up事件的类

public class TextOnTouchEvent extends LinkMovementMethod {
    private static MovementMethod sInstance;
    private OnTouchEvent touchEvent;

    public static MovementMethod getInstance() {
        if (sInstance == null)
            sInstance = new TextOnTouchEvent();

        return sInstance;
    }

    public void setOnTouchEvent(OnTouchEvent touchEvent) {
        this.touchEvent = touchEvent;
    }

    @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);

            ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);
            if (action == MotionEvent.ACTION_UP) {
                touchEvent.onUp();
            }
            if (links.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    links[0].onClick(widget);
                }

                if (action == MotionEvent.ACTION_DOWN) {
                    touchEvent.onDown();
                    Selection.setSelection(buffer, buffer.getSpanStart(links[0]), buffer.getSpanEnd(links[0]));
                }
                return true;
            } else {
                Selection.removeSelection(buffer);
            }
        }
        return super.onTouchEvent(widget, buffer, event);
    }

    public interface OnTouchEvent {
        void onDown();

        void onUp();
    }
}

对一系列对TextView的操作进行封装

/**
 * example:
 * content:Glad to see you @xxx, we will cooperate with you.
 * startIndex:16
 * endIndex:20
 */

public class TextViewSpan {

    public static Builder create() {
        return new Builder();
    }

    private TextViewSpan(Builder builder) {

    }

    public static class Builder {
        private TextView textView;
        private int startIndex;
        private int endIndex;
        private SpannableStringBuilder ssBuilder;

        public Builder setTextView(TextView textView) {
            this.textView = textView;
            return this;
        }

        public Builder setStartIndex(int startIndex) {
            this.startIndex = startIndex;
            return this;
        }

        public Builder setEndIndex(int endIndex) {
            this.endIndex = endIndex;
            return this;
        }

        public Builder setSsBuilder(String content) {
            this.ssBuilder = new SpannableStringBuilder(content);
            return this;
        }

        /**
         * init @xxx
         *
         * @param spans ClickableSpan...
         */
        public Builder setInitSpans(final CharacterStyle... spans) {
            if (textView == null || ssBuilder == null) {
                return this;
            }
            for (CharacterStyle span : spans) {
                if (span == null) {
                    continue;
                }
                ssBuilder.setSpan(span, startIndex, endIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                textView.setText(ssBuilder);
            }
            return this;
        }

        /**
         * when touch @xxx
         *
         * @param spans ClickableSpan...
         */
        public Builder setTouchSpans(final CharacterStyle... spans) {
            if (textView == null || ssBuilder == null) {
                return this;
            }
            TextOnTouchEvent textOnTouchEvent = (TextOnTouchEvent) TextOnTouchEvent.getInstance();
            textOnTouchEvent.setOnTouchEvent(new TextOnTouchEvent.OnTouchEvent() {
                @Override
                public void onDown() {
                    for (CharacterStyle span : spans) {
                        if (span == null) {
                            continue;
                        }
                        ssBuilder.setSpan(span, startIndex, endIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                        textView.setText(ssBuilder);
                    }
                }

                @Override
                public void onUp() {
                    for (CharacterStyle span : spans) {
                        if (span == null) {
                            continue;
                        }
                        ssBuilder.removeSpan(span);
                        textView.setText(ssBuilder);
                    }
                }
            });
            textView.setMovementMethod(textOnTouchEvent);
            return this;
        }

        /**
         * when click @xxx
         *
         * @param listener OnClickListener
         */
        public Builder setOnClickListener(OnClickListener listener) {
            if (textView == null || ssBuilder == null) {
                return this;
            }
            if (listener == null) {
                return this;
            }
            ssBuilder.setSpan(new TClickSpan(listener), startIndex, endIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
            textView.setText(ssBuilder);
            return this;
        }

        public TextViewSpan build() {
            return new TextViewSpan(this);
        }

        private class TClickSpan extends ClickableSpan {
            private OnClickListener listener;


            private TClickSpan(OnClickListener listener) {
                this.listener = listener;
            }

            @Override
            public void onClick(View widget) {
                listener.onClick();
            }

            @Override
            public void updateDrawState(TextPaint ds) {

            }
        }
    }

    public interface OnClickListener {
        void onClick();
    }
}

使用如下

TextView textView = findViewById(R.id.content);
String str = "Glad to see you @xxx, we will cooperate with you.";
TextViewSpan.create()
                .setTextView(textView)
                .setStartIndex(str.indexOf("@"))
                .setEndIndex(str.indexOf("@") + 4)
                .setSsBuilder(str)
                .setInitSpans(new ForegroundColorSpan(Color.parseColor("#06A4D2")))
                .setTouchSpans(new ForegroundColorSpan(Color.parseColor("#FF8650")))
                .setOnClickListener(new TextViewSpan.OnClickListener() {
                    @Override
                    public void onClick() {
                        Log.e("whw", "click");
                    }
                })
                .build();