package com.example.abner.textviewselector; import android.content.Context; import android.graphics.Color; import android.graphics.Typeface; import android.support.annotation.NonNull; import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.text.style.BackgroundColorSpan; import android.text.style.ClickableSpan; import android.text.style.StyleSpan; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import android.widget.Toast; /** * Created by Abner on 15/6/17. * QQ 230877476 * Email nimengbo@gmail.com */ public class CommentTextView extends TextView { private TextView instance; private Context mContext; private StyleSpan boldSpan; //回复者 private ClickableSpan reviewSpan; //被回复者 private ClickableSpan replySpan; public CommentTextView(Context context) { super(context); mContext = context; initView(); } public CommentTextView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; initView(); } public CommentTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; initView(); } private void initView() { instance = this; setHighlightColor(getResources().getColor(R.color.transparent)); setMovementMethod(LinkMovementMethod.getInstance()); boldSpan = new StyleSpan(Typeface.BOLD); reviewSpan = new ClickableSpan() { @Override public void onClick(View widget) { CommentModel model1 = (CommentModel) widget.getTag(); Toast.makeText(mContext, model1.getReviewUName(), Toast.LENGTH_SHORT).show(); } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setTypeface(Typeface.DEFAULT_BOLD); ds.setUnderlineText(false); ds.setColor(getResources().getColor(R.color.blue_666e8a)); } }; replySpan = new ClickableSpan() { @Override public void onClick(View widget) { CommentModel model1 = (CommentModel) widget.getTag(); Toast.makeText(mContext, model1.getReplyUName(), Toast.LENGTH_SHORT).show(); } @Override public void updateDrawState(@NonNull TextPaint ds) { super.updateDrawState(ds); ds.setTypeface(Typeface.DEFAULT_BOLD); ds.setUnderlineText(false); ds.setColor(getResources().getColor(R.color.blue_666e8a)); } }; } private TextBlankClickListener listener; public void setListener(TextBlankClickListener listener) { this.listener = listener; } private int mStart = -1; private int mEnd = -1; private android.os.Handler handler = new android.os.Handler(); //计数 private int leftTime; private Runnable countDownRunnable = new Runnable() { public void run() { leftTime--; if (leftTime == -1) { // 触发长按事件 if(listener != null && !isMove){ listener.onLongClick(instance); } } else { //100毫秒执行一次 超过500毫秒就说明触发长按 handler.postDelayed(this, 100); } } }; private boolean isMove = false; private float lastX; private float lastY; @Override public boolean onTouchEvent(MotionEvent event) { boolean result = super.onTouchEvent(event); int action = event.getAction(); int x = (int) event.getX(); int y = (int) event.getY(); if (action == MotionEvent.ACTION_DOWN) { lastX = event.getX(); lastY = event.getY(); isMove = false; } else if (action == MotionEvent.ACTION_MOVE) { float distanceX = Math.abs(lastX - event.getX()); float distanceY = Math.abs(lastY - event.getY()); if (distanceX > 1.5f || distanceY > 1.5f) { isMove = true; // return result; } } x -= getTotalPaddingLeft(); y -= getTotalPaddingTop(); x += getScrollX(); y += getScrollY(); Layout layout = getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); CharSequence text = getText(); if (TextUtils.isEmpty(text) || !(text instanceof Spannable)) { return result; } Spannable buffer = (Spannable) text; ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { if (action == MotionEvent.ACTION_DOWN) { mStart = buffer.getSpanStart(link[0]); mEnd = buffer.getSpanEnd(link[0]); if (mStart >= 0 && mEnd >= mStart) { buffer.setSpan(new BackgroundColorSpan(Color.GRAY), mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (mStart >= 0 && mEnd >= mStart) { buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT), mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mStart = -1; mEnd = -1; } } return true; } else { if (mStart >= 0 && mEnd >= mStart) { buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT), mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mStart = -1; mEnd = -1; } if (action == MotionEvent.ACTION_DOWN) { setBackgroundColor(Color.GRAY); //开始计数 leftTime = 5; handler.post(countDownRunnable); return true; } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { setBackgroundColor(Color.TRANSPARENT); //如果没有调用长按 调用点击整个的监听 if (leftTime > -1) { leftTime = 10; handler.removeCallbacks(countDownRunnable);//移除统计 if (listener != null && !isMove) { listener.onBlankClick(this); } } } else if (action == MotionEvent.ACTION_MOVE) { if (isMove) { setBackgroundColor(Color.TRANSPARENT); } } Selection.removeSelection(buffer); return result; } } /** * 设置回复的可点击文本 * * @param model * @return */ public void setReply(CommentModel model) { setText(""); setTag(model); String reviewName = model.getReviewUName(); SpannableStringBuilder stylesBuilder; String str; if (model.getReplyUid() != 0) { String replyName = model.getReplyUName(); str = reviewName + "回复" + replyName + ":" + model.getReviewContent(); int reviewStart = str.indexOf(reviewName); int replyStart = str.indexOf(replyName); stylesBuilder = new SpannableStringBuilder(str); stylesBuilder.setSpan(reviewSpan, reviewStart, reviewStart + reviewName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); stylesBuilder.setSpan(replySpan, replyStart, replyStart + replyName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { str = reviewName + ":" + model.getReviewContent(); int reviewStart = str.indexOf(reviewName); stylesBuilder = new SpannableStringBuilder(str); stylesBuilder.setSpan(reviewSpan, reviewStart, reviewStart + reviewName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } append(stylesBuilder); } }