Android直播聊天之图文混排式TextView

在看某些直播时,会发现我们发送的聊天信息呈现的样式还是很利用空间的,此文做了相关界面的实现,截图如下:

Activity里实现主要涉及自定义Drawable和自定义DrawableSpan,并配合SpannableStringBuilder,代码如下:

TextView textView = findViewById(R.id.textView);
String userFlag = "VIP用户";
final String PLACEHOLDER = " ";
String flag = PLACEHOLDER + userFlag + PLACEHOLDER;
String username = "慕容:";
String content = "人若真能转世 世间若真有轮回" +
				"那麽 我的爱 我们前世曾经是什麽\n" +
				"你 若曾是江南采莲的女子\n" +
				"我 必是你皓腕下错过的那朵\n" +
				"你 若曾是逃学的顽童\n" +
				"我 必是从你袋中掉下的那颗崭新的弹珠 ";
TextDrawable textDrawable = new TextDrawable(Color.BLUE, flag, Color.WHITE, textView.getTextSize());
SpannableStringBuilder builder = new SpannableStringBuilder(flag).append(username).append(content);
builder.setSpan(new TextDrawableSpan(textDrawable), 0, flag.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new ForegroundColorSpan(Color.GRAY), flag.length(),
		flag.length() + username.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(builder);

TextDrawable代码如下:

import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextPaint;

public class TextDrawable extends Drawable {
    private Paint mBgPaint;
    private TextPaint mTextPaint;
    private String mText;
    private RectF mRect;

    public TextDrawable(@ColorInt int solidColor, String text, @ColorInt int textColor, float textSize) {
        mText = text;
        mRect = new RectF();
        //初始化背景画笔
        if (solidColor != 0) {
            mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mBgPaint.setColor(solidColor);
            mBgPaint.setStyle(Paint.Style.FILL);
        }
        //初始化文字画笔
        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setColor(textColor);
        mTextPaint.setTextSize(textSize);
        mTextPaint.setStyle(Paint.Style.FILL);
        //调整此drawable的边界,修改的值将存入getBounds里的矩阵里去
        Rect rect = getBounds();
        rect.set(0, 0, (int) mTextPaint.measureText(text),
                mTextPaint.getFontMetricsInt().bottom - mTextPaint.getFontMetricsInt().top);
    }

    @Override
    public void draw(@NonNull Canvas canvas) {
        drawBg(canvas);
        drawText(canvas);
    }

    /**
     * draw背景
     */
    private void drawBg(Canvas canvas) {
        if (mBgPaint == null)
            return;
        //画圆角矩形作为背景图
        Rect rect = getBounds();
        mRect.set(rect);
        float radius = (rect.bottom - rect.top) / 2;
        canvas.drawRoundRect(mRect, radius, radius, mBgPaint);
    }

    /**
     * draw文本
     */
    private void drawText(Canvas canvas) {
        Rect rect = getBounds();
        Paint.FontMetrics metrics = new Paint.FontMetrics();
        mTextPaint.getFontMetrics(metrics);
        float textWidth = mTextPaint.measureText(mText);
        float x = (rect.right - rect.left - textWidth) / 2;
        float textHeight = metrics.bottom - metrics.top;
        float y = (rect.bottom - rect.top - textHeight) / 2 - metrics.top;
        //计算开始绘制x值,和基线baseline的y值,实现居中文本的效果
        canvas.drawText(mText, x, y, mTextPaint);
    }

    @Override
    public void setAlpha(int alpha) {
        if (mBgPaint != null) {
            mBgPaint.setAlpha(alpha);
        }
        mTextPaint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {
        if (mBgPaint != null) {
            mBgPaint.setColorFilter(colorFilter);
        }
        mTextPaint.setColorFilter(colorFilter);
    }

    @Override
    public int getOpacity() {
        //TRANSLUCENT表示只有绘制的地方才覆盖底下的内容
        return PixelFormat.TRANSLUCENT;
    }

}

TextDrawableSpan代码如下:

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.text.style.DynamicDrawableSpan;

/**
 * 继承DynamicDrawableSpan是为了使默认居底部或基线的效果更改成居中的效果,主要是重写其draw方法
 */
public class TextDrawableSpan extends DynamicDrawableSpan {

    private Drawable drawable;

    public TextDrawableSpan(@NonNull Drawable drawable) {
        this.drawable = drawable;
    }

    @Override
    public Drawable getDrawable() {
        return drawable;
    }

    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end,
                     float x, int top, int y, int bottom, @NonNull Paint paint) {
        //注掉父类绘制的效果,居底部或位于基线
//        super.draw(canvas, text, start, end, x, top, y, bottom, paint);
        Drawable d = getDrawable();
        canvas.save();
        Rect bounds = d.getBounds();
        float dy = (bottom - bounds.bottom) * 0.5f;
        canvas.translate(x, dy);
        d.draw(canvas);
        canvas.restore();
    }

}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值