只包裹文本的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

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