前言
我们现在在 Android App 中几乎天天都能见到 ImageSpan
,比如 App 自定义的 emoji 表情和文本中带的一些小图标等。
你可能要问了既然都有 emoji 了,为啥还要自定义呢,输入法里的 emoji 和 ImageSpan 的有啥不一样呢?
。要做这玩意儿肯定还是产品提的需求啦,想自己原创一些比较 贱
的表情吧。现在好多输入法都自带的 emoji 只是一串字符,TextView
在渲染的时候会用系统自带的表情把它们画出来,而ImageSpan
的话就需要自己手动画对应的图片。
我在使用ImageSpan
的过程中也遇到了一些坑,在这里就做下总结,分享出来,有什么不对的地方,也请各路大佬批评指正。
ImageSpan
1、ImageSpan 来自 ReplacementSpan
ReplacementSpan
中空实现了updateMeasureState
和updateDrawState
/**
* This method does nothing, since ReplacementSpans are measured
* explicitly instead of affecting Paint properties.
*/
public void updateMeasureState(TextPaint p) {
}
/**
* This method does nothing, since ReplacementSpans are drawn
* explicitly instead of affecting Paint properties.
*/
public void updateDrawState(TextPaint ds) {
}
而新增了getSize
和draw
来进行图片位置的确定以及图片内容的绘制
/**
* Returns the width of the span. Extending classes can set the height of the span by updating
* attributes of {@link android.graphics.Paint.FontMetricsInt}. If the span covers the whole
* text, and the height is not set,
* {@link #draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)} will not be
* called for the span.
*
* @param paint Paint instance.
* @param text Current text.
* @param start Start character index for span.
* @param end End character index for span.
* @param fm Font metrics, can be null.
* @return Width of the span.
*/
public abstract int getSize(@NonNull Paint paint, CharSequence text,
@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@Nullable Paint.FontMetricsInt fm);
/**
* Draws the span into the canvas.
*
* @param canvas Canvas into which the span should be rendered.
* @param text Current text.
* @param start Start character index for span.
* @param end End character index for span.
* @param x Edge of the replacement closest to the leading margin.
* @param top Top of the line.
* @param y Baseline.
* @param bottom Bottom of the line.
* @param paint Paint instance.
*/
public abstract void draw(@NonNull Canvas canvas, C