只包裹文本的BackgroundColorSpan

作者: 林鹿 | 来源:发表于2017-12-22 11:06 被阅读389次

BackgroundColorSpan可以实现文本加底色的一个效果,没有问题,然而问题是文本增加间距的时候效果会变成这样:


所以我们期望达到的效果是一个只包裹文本的的背景底色。
研究了一下,发现必须得到文本相关的信息,才能在指定的位置填充颜色,所以无法再利用BackgroundColorSpan这个类了,而要用ReplacementSpan,于是有:
public class BorderSpan extends ReplacementSpan {
    private int mWidth;
    private int mBackgroundColor;

    public BorderSpan(@ColorInt int backgroundColor) {
        mBackgroundColor = backgroundColor;
    }

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

    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end,
                     float x, int top, int y, int bottom, @NonNull Paint paint) {
        int color = paint.getColor();
        if (mBackgroundColor != 0) {
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(mBackgroundColor);
            canvas.drawRect(x, top, x + mWidth, bottom, paint);
        }
    }
}

然而发现效果竟然和BackgroundColorSpan一样!显然这里需要在bottom上作文章。这时候需要了解一些字体相关的知识:


并且需要知道的是ascentdescent是相对于baseline的值,所以ascent经常是负值,而对应的类便是Paint.getFontMetrics()FontMetrics, 在类字段描述中有这样一段:

所以最终用到的是这个字段,draw方法需要知道的重要一点是,这里的y就是字体信息对应的baseline,于是有:

    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end,
                     float x, int top, int y, int bottom, @NonNull Paint paint) {
        int color = paint.getColor();
        bottom = (int) (y + paint.getFontMetrics().bottom);
        ....
    }

效果终于达到了:



如果不用bottom而用descent呢?
大家可以试验下,只是包裹的边界很靠近文本而已。

相关文章

  • 只包裹文本的BackgroundColorSpan

    BackgroundColorSpan可以实现文本加底色的一个效果,没有问题,然而问题是文本增加间距的时候效果会变...

  • SpannableString类的常用功能介绍

    1、BackgroundColorSpan 背景色2、ClickableSpan 文本可点击,有点击事件3、For...

  • Android TextView Span属性

    BackgroundColorSpan:给部分文字设置背景颜色 ForegroundColorSpan:给部分文字...

  • Markdown 参考笔记

    1. 标题 井号#前缀视为标题 2. 粗体与斜体 星号 * 包裹的文本视为粗体 下划线_包裹的文本视为斜体 加了斜...

  • Design控件

    TextInputLayout(文本输入布局)TextInputLayout的作用是将EditText包裹起来,使...

  • 简书

    一个#表示一级标题 两个#表示二级标题 最多可以加六个#号 使用四个星号包裹你要加粗的文本使用两个星号包裹的文本会...

  • html基础——2017.2.17

    from:包裹标签,action:# Input:文本框、单选按钮、多选按钮 type:checkbox、提交的按...

  • 简单的标注实现

    标注实现思路 标注系统核心思路将文本遍历替换为标签包裹的文本(list),根据鼠标划过动作获取划词信息(包括:内容...

  • Flutter Text、ListView、ScrollVie

    Text高度自适应核心逻辑 Row+Expanded包裹Text文本 ListView、ScrollView这一类...

  • 第四天

    1、Form:包裹标签,action:# Input:文本框,单选按钮,多选按钮。提交的按钮,按钮,重置的按钮。 ...

网友评论

    本文标题:只包裹文本的BackgroundColorSpan

    本文链接:https://www.haomeiwen.com/subject/ihjtgxtx.html