ReplacementSpan 在 Marshmallow 中不起作用

ReplacementSpan not working in Marshmallow

我使用 ReplacementSpan 为 TextView 添加了文本描边。它在 Marshmallow 下面的 Android Sdk 中运行良好。但是,在棉花糖中它显示空白文本。当我将 ForegroundSpan 添加到 Top TextView,然后将我的自定义跨度设置为下面的视图时,它就可以工作了。我不明白我是否遗漏了什么。
下面是我的 TextSpannable Class 代码 -

public class TextSpannable extends ReplacementSpan {

    private final Paint paintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
    private final Paint paintStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
    private final Path path = new Path();
    private int width;

    public TextSpannable(int strokeWidth) {
       paintFill.setColor(Color.WHITE);
       paintStroke.setStyle(Paint.Style.STROKE);
       paintStroke.setStrokeWidth(6);
    }

    public void setPathEffect(PathEffect effect) {
       paintStroke.setPathEffect(effect);
    }

    @Override
    public int getSize(Paint paint, CharSequence text, int start, 
       int end,   Paint.FontMetricsInt fm) {
       this.paintFill.setColor(Color.WHITE);
       this.paintStroke.setColor(Color.parseColor("#402002"));
       width = (int) (paint.measureText(text, start, end) +  
       this.paintStroke.getStrokeWidth() + paintFill.getTextSize());
       return width;
    }

    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, 
         float x, int top, int y,int bottom, Paint paint) {
        path.reset();
        paint.getTextPath(text.toString(), start, end, x, y, path);
        path.close();

        canvas.translate(this.paintStroke.getStrokeWidth() / 2, 0);
        canvas.drawPath(path,this.paintStroke);
        canvas.drawPath(path, this.paintFill);
        canvas.translate(-this.paintStroke.getStrokeWidth() / 2, 0);
        //canvas.drawText(this.text,start,end,x,y,paintFill);
        //canvas.drawText(this.text,start,end,x,y,paintStroke);
     }
}

这就是我将其设置为 TextView 的方式 -

    spannableString7 = 
    new SpannableStringBuilder(getString(R.string.string1));
    ForegroundColorSpan fcs  =new ForegroundColorSpan(Color.TRANSPARENT);
    spannableString7.setSpan(fcs,0, getString(R.string.string1).length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
    textSpam.setText(spannableString7, TextView.BufferType.SPANNABLE);    

   //when I comment above block, text becomes blank in Textview

    spannableString1 = 
    new SpannableStringBuilder(getString(R.string.string1));
    spannableString1.setSpan(textSpannable,0,getString(R.string.string1).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    textView.setText(spannableString1, TextView.BufferType.SPANNABLE);

我想出了如何让它发挥作用。 您必须实施 LineHeightSpan 因为如果您单独使用 ReplacementSpan 那么我想 TextView 不知道您的文本有多少高度? 只需实施 LineHeightSpan 即可解决问题。

public class CoolBackgroundColorSpan extends ReplacementSpan implements LineHeightSpan {

    @Override
    public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
        // Your code here
    }

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

    @Override
    public void chooseHeight(CharSequence charSequence, int i, int i1, int i2, int i3, Paint.FontMetricsInt fontMetricsInt) {
        // This method is needed because the class implements LineHeightSpan.
        // We don't modify the fontMetricsInt because we don't want to modify the line height.
        // The line height will have the height of the text
    }

}

如果您还想更改行高,请参阅此答案

实施 LineHeightSpan(根据 vovahost 的回答)并不总是能正常工作。有时高度计算不正确,导致文本在顶部被剪切。

一个可能的解决方法是让 SpannableStringBuilder 包含除 ReplacementSpan 之外的其他内容。可以向文本附加一个零宽度 space,因此它看起来没有变化,但可以通过 TextView 正确测量和显示,例如:

spannableString1 = 
    new SpannableStringBuilder(getString(R.string.string1));
spannableString1.setSpan(textSpannable,0,getString(R.string.string1).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

spannableString1.append('\u200B'); // <-- append a zero-width space

textView.setText(spannableString1, TextView.BufferType.SPANNABLE);