Android 文字带拼音

项目使用,自定义ReplaceSpan,使用富文本方式,定义好协议,显示中文汉字上带拼音功能

public class PYTextSpan extends ReplacementSpan {
    // 解析标签
    public static final String TAG_PY_TEXT = "span";
    // 拼音标签,拼音内容
    public static final String TAG_PY_CONTENT = "data-pinyin";
    // Span尺寸
    private int mSize;
    // 拼音内容
    private String mPYContent = "";
    // 拼音的画笔
    private Paint mPYPaint = new Paint();
    private Paint mBgPaint = new Paint();
    // 拼音和文字的间距
    private final int mPyTextPadding = DimenUtils.dp2pxInt(1f);
    // 拼音的字体大小
    private int mPyFontSize = 0;
    private boolean mAddBg;

    public PYTextSpan(Attributes attributes) {
        initView(attributes);
    }

    @Override
    public int getSize(@NonNull Paint paint,
                       CharSequence text,
                       int start,
                       int end,
                       Paint.FontMetricsInt fm) {
        int textWidth = (int) paint.measureText(text, start, end);
        if (mPyFontSize > 0) {
            mPYPaint.setTextSize(mPyFontSize);
        } else {
            // 没有配置拼音字体大小,默认取字大小的2/3
            mPYPaint.setTextSize((paint.getTextSize() / 3) * 2);
        }
        mPYPaint.setColor(paint.getColor());
        // 判单当前字符是否为汉字
        boolean isChinese = HtmlTextViewUtils.isChinese(text.subSequence(start, end)
                                                            .toString()
                                                            .trim());
        // 汉字默认使用最长的拼音6位,标点符号默认不做处理
        int pyWidth = (TextUtils.isEmpty(mPYContent) && !isChinese)
                      ? 0
                      : (int) mPYPaint.measureText("zhuang");
        // 考虑后续可能会设置拼音字体大小,所以取最大
        mSize = Math.max(textWidth, pyWidth);
        if (fm != null) {
            Paint.FontMetricsInt pyFontMetrics = mPYPaint.getFontMetricsInt();
            int pyHeight = pyFontMetrics.descent - pyFontMetrics.ascent;
            // 加了文字,所以测量时要加上文字的高度
            fm.bottom += (pyHeight + mPyTextPadding);
            fm.descent += (pyHeight + mPyTextPadding);
        }
        return mSize;
    }

    @Override
    public void draw(@NonNull Canvas canvas,
                     CharSequence text,
                     int start,
                     int end,
                     float x,
                     int top,
                     int y,
                     int bottom,
                     Paint paint) {
        drawPYText(canvas, text, start, end, x, y, top, bottom, paint);
    }

    private void drawPYText(Canvas canvas,
                            CharSequence rawText,
                            int start,
                            int end,
                            float x,
                            int y,
                            int top,
                            int bottom,
                            Paint paint) {
        // 行高
        int lineHeight = bottom - top;
        paint.setAntiAlias(true);
        //居中
        mPYPaint.setTextAlign(Paint.Align.CENTER);
        paint.setTextAlign(Paint.Align.CENTER);
        Paint.FontMetricsInt textFontMetrics = paint.getFontMetricsInt();
        Paint.FontMetricsInt pyFontMetrics = mPYPaint.getFontMetricsInt();
        int textHeight = textFontMetrics.descent - textFontMetrics.ascent;
        int pyHeight = pyFontMetrics.descent - pyFontMetrics.ascent;
        // 因为设置了居中,所以XY都要对应加1/2
        int pyStartY = top + (lineHeight - textHeight - pyHeight) / 2 + pyHeight / 2 + mPyTextPadding * 2;
        int textStartY = pyStartY + pyHeight + mPyTextPadding + (textHeight - pyHeight) / 2;
        final String currentText = rawText.subSequence(start, end).toString();
        float startX = x + (mSize / 2);
        // 绘制拼音及文字
        canvas.drawText(mPYContent, startX, pyStartY, mPYPaint);
        // 题干中也有可能含有字母a,这里判断如果是就替换字体
        if (currentText.equals("a")
            || currentText.equals("ā")
            || currentText.equals("á")
            || currentText.equals("ǎ")
            || currentText.equals("à")) {
            paint.setTypeface(Typeface.createFromAsset(GlobalApplicationProvider.INSTANCE.getApplicationContext()
                                                                                         .getAssets(), "fonts/cn_py.ttf"));
            // 新字体库比原生字体大小更大,有可能会被裁剪一些,所以减一点字体大小
            paint.setTextSize(paint.getTextSize() - 3);
        }
        canvas.drawText(currentText, startX, textStartY, paint);
        if (mAddBg) {
            mBgPaint.setColor(Color.parseColor("#3DFCD043"));
            canvas.drawRect(startX - (mSize / 2), pyStartY, startX + (mSize / 2) + 1, pyStartY + textHeight, mBgPaint);
        }
    }

    private void initView(Attributes attrs) {
        mPYContent = getPYContent(attrs);
        mPYPaint.setAntiAlias(true);
        mPYPaint.setTypeface(Typeface.createFromAsset(GlobalApplicationProvider.INSTANCE.getApplicationContext()
                                                                                        .getAssets(), "fonts/cn_py.ttf"));
    }

    /**
     * 设置拼音字体大小
     */
    public void setPyTextSize(int fontSize) {
        mPyFontSize = fontSize;
    }

    /**
     * 获取拼音内容
     */
    private String getPYContent(Attributes attributes) {
        if (attributes == null) {
            return "";
        }
        String pyContent = attributes.getValue(TAG_PY_CONTENT);
        return TextUtils.isEmpty(pyContent) ? "" : pyContent;
    }

    public void setBg(boolean addBg) {
        this.mAddBg = addBg;
    }

    public boolean getAddBg() {
        return mAddBg;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值