之前写过一篇图文混排的,算法就是通过计算文本宽及行数,在换行的时候截取文本剩余的部分显示在图片下边,
代码下载:demo
今天这边是工作共常用到的,标签在前或在最后显示,比如帖子前边显示多个标签表示精华帖、优秀帖、解决标签等;其实主要是重写DynamicDrawableSpan,以及通过设置SpanableStringBuilder,来显示的。
先上图
代码如下:
主要是将普通文本替换成图片文本之后(spannaableString)追加到文本后边
/**
* 添加标签
*
* @param tagIconPosition 将标签放在文本的前面或者后边
* @param tagDrawableIdList 本地标签的drawableId集合
*/
private CharSequence addTagText(final int tagIconPosition, final List tagDrawableIdList, CharSequence emojiText) {
if (tagDrawableIdList == null || tagDrawableIdList.size() == 0) {
return emojiText;
}
setText(emojiText);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("");
for (int i = 0; i spannableStringBuilder.append("t ");
}
for (int i = 0; i int resourceId = tagDrawableIdList.get(i);
TagSpan tagSpanned = new TagSpan(context, resourceId, (int) getTextSize(), TagSpan.ALIGN_BASELINE, (int) getTextSize());
spannableStringBuilder.setSpan(tagSpanned, i * 2, i * 2 + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
CharSequence sepText = getText();
if (tagIcOnPosition== START) {//icon显示在前面
spannableStringBuilder.append(sepText);
} else {
spannableStringBuilder.insert(0, sepText);
}
// setText(spannableStringBuilder);//最后设置
return spannableStringBuilder;
}
重写DynamicDrawableSpan类,设置tag的位置,主要是因为用原生的Span会有边界错位的问题,所以要重写onDraw()
代码如下:也不复杂,计算方式自己根据需要调整
public Drawable getDrawable() {
if (mDrawable == null) {
try {
mDrawable = mContext.getResources().getDrawable(mResourceId);
mHeight = mSize;
mWidth = mHeight * mDrawable.getIntrinsicWidth() / mDrawable.getIntrinsicHeight();
mTop = (mTextSize - mHeight) / 2;
// 设置边界还是会导致错位
mDrawable.setBounds(0, mTop, mWidth, mTop + mHeight);
} catch (Exception e) {
// swallow
}
}
return mDrawable;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
//super.draw(canvas, text, start, end, x, top, y, bottom, paint);
Drawable b = getCachedDrawable();
canvas.save();
int transY = bottom - b.getBounds().bottom;
if (mVerticalAlignment == ALIGN_BASELINE) {// 绘制图片的位置
transY = top + ((bottom - top) / 2) - ((b.getBounds().bottom - b.getBounds().top) / 2) - mTop;
}
// 由于图片会错位,所以要移动这个画布
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
现在说另一种实现方式:不过就是因为这种实现方式有错位问题,才使用方式一的,但是有些情况不需要自定义DynamicDrawableSpan就可以插入文本的,多学点无坏处吧,一并写下来说不定以后对自己有帮助
实现方式是通过Html.fromHtml( text,imageGetter);实现的;
代码如下:
1 、实现一个html转化时需要的imageGetter,主要用于识别html 带有的标签
/**
* 注:在异步线程中:先将文本表情转换成charsequence,然后加载icon,再者将icon放在文本表情的前或后,最后通过handler在主线程中设置textview 下午8:47:02 Spanned
*/
private Spanned convertTagToIconSpanned(CharSequence emojiText, int tagIconPosition, List tagDrawablIds) {
StringBuilder temp = new StringBuilder();
for (int i : tagDrawablIds) {//先将drawId转成html标签,
temp.append(" ");
}
Spanned tagSpanned = Html.fromHtml(temp.toString(), getImageGetterInstance(), null);
if (tagIcOnPosition== START) {// 本地图片放在文本前边
SpannableStringBuilder span = new SpannableStringBuilder(tagSpanned);
span.append(emojiText);
return span;
} else if (tagIcOnPosition== END) {// 本地图片放在文本后边
SpannableStringBuilder span = new SpannableStringBuilder(emojiText);
span.append(tagSpanned);
return span;
}
return new SpannableStringBuilder(emojiText);
}
2、获取标签的图片
/**
* ImageGetter用于text图文混排
*
* @return
*/
public ImageGetter getImageGetterInstance() {
ImageGetter imgGetter = new ImageGetter() {
@Override
public Drawable getDrawable(String source) {// 可用于加载本地图片和网络图片,source就是标签设置的 src的值
int fOntH= (int) (getTextSize());
int id = Integer.parseInt(source);
Drawable d = drawableMap.get(id);
if (d == null) {
d = getResources().getDrawable(id);
drawableMap.put(id, d);
}
int height = fontH;
int width = (int) ((float) d.getIntrinsicWidth() / (float) d.getIntrinsicHeight()) * fontH;
if (width == 0) {
width = d.getIntrinsicWidth();
}
d.setBounds(0, 0, width, height);
return d;
}
};
return imgGetter;
}
3,通过html转化成 Spanned ;用于setText(),就完成设置了
Spanned tagSpanned = Html.fromHtml(temp.toString(), getImageGetterInstance(), null);
希望对你有一点帮助
多标签Demo