Android ClickableRoundedBackground Span实现(初版)

一、自定义圆角背景span


import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.style.ReplacementSpan;
import android.view.View;

public abstract class RoundedBackgroundSpan extends ReplacementSpan  {
  private static int CORNER_RADIUS = 10;
  private int backgroundColor = 0;
  private int textColor = 0;

  public RoundedBackgroundSpan(int backgroundColor, int textColor) {
    this.backgroundColor = backgroundColor;
    this.textColor = textColor;
  }

  @Override
  public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {

    return Math.round(paint.measureText(text, start, end));
  }

  @Override
  public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
                   int bottom, Paint paint) {
    RectF rectF = new RectF(x , top - 8, x + measureText(paint, text, start, end) - 10, y + 16);
    paint.setColor(backgroundColor);
    canvas.drawRoundRect(rectF, CORNER_RADIUS, CORNER_RADIUS, paint);
    paint.setColor(textColor);

    canvas.drawText(text, start, end, x, y, paint);
  }

  private float measureText(Paint paint, CharSequence text, int start, int end) {
    return paint.measureText(text, start, end);
  }

  public abstract void onClick(View view);
}

二、集成ClickableMovementMethod


import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.MotionEvent;
import android.widget.TextView;

public class ClickableMovementMethod extends LinkMovementMethod{
  private static ClickableMovementMethod sInstance;
  public static ClickableMovementMethod getInstance() {
    if (sInstance == null) {
      sInstance = new ClickableMovementMethod();
    }
    return sInstance;
  }

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

      RoundedBackgroundSpan[] roundedBackgroundSpans = buffer.getSpans(off, off, RoundedBackgroundSpan.class);
      if (roundedBackgroundSpans.length != 0) {
        if (action == MotionEvent.ACTION_UP) {
          roundedBackgroundSpans[0].onClick(widget);
        } else if (action == MotionEvent.ACTION_DOWN) {
          Selection.setSelection(buffer, buffer.getSpanStart(roundedBackgroundSpans[0]), buffer.getSpanEnd(roundedBackgroundSpans[0]));
        }
        return true;
      } else {
        Selection.removeSelection(buffer);
      }
    }
    return false;
  }
}

三、将2者融合起来



import android.view.View;

/**
 * Created by ningdai.cx on 15/11/26.
 */
public class ClickableRoundedBackgroundSpan extends RoundedBackgroundSpan {

  public ClickableRoundedBackgroundSpan(int backgroundColor, int textColor) {
    super(backgroundColor, textColor);
  }

  @Override
  public void onClick(View view) {

  }
}

四、具体使用场景

   TextView mTipContentTextView = (TextView) mActivity.findViewById(R.id.tip_content_text);
   ......
 // 设置MovementMethod;  mTipContentTextView.setMovementMethod(ClickableMovementMethod.getInstance());
 // 新增SpannableString
    SpannableString tagSpan = new SpannableString(tipContent);
    int spanStartIndex;
    int spanEndIndex;
    int textColor = Color.parseColor("#666666");
    int bgColor = Color.parseColor("#F5F5F5");
    // 遍历需要变成圆角点击的tag列表
    for (final String tag : tagArray) {
      spanStartIndex = tipContent.indexOf(tag);
      spanEndIndex = spanStartIndex + tag.length();
      // 为SpannableString设置Span样式及点击事件
      tagSpan.setSpan(new ClickableRoundedBackgroundSpan(bgColor, textColor) {
                        @Override
                        public void onClick(View view) {
                          Toast.makeText(mActivity.getApplicationContext(), "U clicked " + tag,
                                         Toast.LENGTH_SHORT).show();
                          mTagClickListener.onTagClick(tag);
                        }
                      }, spanStartIndex, spanEndIndex,
                      Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
    mTipContentTextView.setText(tagSpan);
    mTipContentTextView.setLineSpacing(0, 1.5f);

先把实现方案记录下来,具体原理可参见Android API 都讲的比较详细。

你可能感兴趣的:(android)