1 简介
之前已经讲过TextView的基础知识、段落级别的Span和字符级别的Span,分析了Android提供的一些Span的源码,这篇文字讲解如何自定义Span。
这篇文章中,由于段落级别的Span比较简单,在这不讲述这个类型的自定义Span。这篇着重讲述字符级的Span,并且结合Android提供动画机制制作出十分酷炫的动画Span。
2 FrameSpan
FrameSpan实现给相应的字符序列添加边框的效果,整体思路其实比较简单。
计算字符序列的宽度;
根据计算的宽度、上下坐标、起始坐标绘制矩形;
绘制文字
展现效果如下所示:
FrameSpan
再来看一下代码,其实代码十分简单。
public class FrameSpan extends ReplacementSpan {
private final Paint mPaint;
private int mWidth;
public FrameSpan() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLUE);
mPaint.setAntiAlias(true);
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
//return text with relative to the Paint
mWidth = (int) paint.measureText(text, start, end);
return mWidth;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
//draw the frame with custom Paint
canvas.drawRect(x, top, x + mWidth, bottom, mPaint);
canvas.drawText(text, start, end, x, y, paint);
}
}
在这再次说明一下draw方法里面的参数的意义。
canvas:用来绘制的画布;
text:整个text;
start:这个Span起始字符在text中的位置;
end:这个Span结束字符在text中的位置;
x:这个Span的其实水平坐标;
y:这个Span的baseline的垂直坐标;
top:这个Span的起始垂直坐标;
bottom:这个Span的结束垂直坐标;
paint:画笔
3 VerticalImageSpan
Google提供的ImageSpan和DynamicDrawableSpan只能实现图片和文字底部对齐或者是baseline对齐,现在VerticalImageSpan可以实现图片和文字居中对齐。
VerticalImageSpan
图中的图片保持了和文字居中对齐,现在来看看VerticalImageSpan的源码。
public class VerticalImageSpan extends ImageSpan {
private Drawable drawable;
public VerticalImageSpan(Drawable drawable) {
super(drawable);
this.drawable=drawable;
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fontMetricsInt) {
Drawable drawable = getDrawable();
if(drawable==null){
drawable= this.drawable;
}
Rect rect = drawable.getBounds();
if (fontMetricsInt != null) {
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.bottom - fmPaint.top;
int drHeight = rect.bottom - rect.top;
int top = drHeight / 2 - fontHeight / 4;
int bottom = drHeight / 2 + fontHeight / 4;
fontMetricsInt.ascent = -bottom;
fontMetricsInt.top = -bottom;
fontMetricsInt.bottom = top;
fontMetricsInt.descent = top;
}
ret