Android——SpannableString字体大小不一致垂直居中

SpannableString来实现TextView的富文本效果(改变字体大小,设置颜色,设置图片,设置超链接效果等等),大家应该都已经用过很多次了。这里不再详述,今天我们主要讨论,当TextView中的文本字体大小不一致时如何垂直居中。

首先,我们需要明确TextView绘制的基本度量标准,如下图:
Android——SpannableString字体大小不一致垂直居中_第1张图片
各个字段的具体解释可以参考这篇文章,写的非常详细。
https://blog.csdn.net/u010983881/article/details/53995020
默认情况下,TextView的文字都是底部对齐的,当字体大小不一致时,效果如下:
Android——SpannableString字体大小不一致垂直居中_第2张图片
通过了解图1中的各个字段含义之后,我们知道,我们可以通过重设TextView某些文字的Y坐标来实现他在整个TextView中垂直居中的效果。代码如下:
VerticalAlignTextSpan.java

public class VerticalAlignTextSpan extends ReplacementSpan {
    private int fontSizeSp = -1;//单位:sp

    public VerticalAlignTextSpan() {
    }

    public VerticalAlignTextSpan(int fontSizeSp) {
        this.fontSizeSp = fontSizeSp;
    }

    @Override
    public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) {
        Paint newPaint = getCustomTextPaint(paint);
        return (int) newPaint.measureText(text, start, end);
    }

    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int
            bottom, @NonNull Paint paint) {
        Paint newPaint = getCustomTextPaint(paint);
        Paint.FontMetricsInt fontMetricsInt = newPaint.getFontMetricsInt();
        int offsetY = (y + fontMetricsInt.ascent + y + fontMetricsInt.descent) / 2 - (top + bottom) / 2;
        Log.d("VerticalAlignTextSpan", "offsetY-> " + offsetY);
        canvas.drawText(text, start, end, x, y - offsetY, newPaint);
    }

    private TextPaint getCustomTextPaint(Paint srcPaint) {
        TextPaint textPaint = new TextPaint(srcPaint);
        if (fontSizeSp != -1) {//-1没有重设fontSize
            textPaint.setTextSize(fontSizeSp * textPaint.density);//sp转px
        }
        return textPaint;
    }
}

MainActivity.java

SpannableString ss = new SpannableString("900米");
Drawable drawable = getResources().getDrawable(R.drawable.cattle);
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
AbsoluteSizeSpan bigFontSpan = new AbsoluteSizeSpan(40, true);
ss.setSpan(bigFontSpan, 0, ss.length() - 1, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
VerticalAlignTextSpan verticalAlignTextSpan = new VerticalAlignTextSpan(23);
ss.setSpan(verticalAlignTextSpan, ss.length() - 1, ss.length(), SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
tvImageSpan.setText(ss);

最终效果如下:
Android——SpannableString字体大小不一致垂直居中_第3张图片

你可能感兴趣的:(Android,Android,TextView,富文本,垂直居中)