如何在 TextView 外部添加描边

How to add stroke on outside of TextView

欢迎任何想法、代码片段!

我创建了一个扩展 AppCompatTextViewCustomTextView class,我这样做是为了添加 stroke 对无聊 TextView 的支持].问题是,Paint.Style.STROKETextView 的内侧添加了笔画。应该有一些东西可以让我们在外划和内划之间进行选择。

P.S:如果需要,我可以分享完整的 CustomTextView class,没什么大不了的。

这是我们 CustomTextView 中的 onDraw 方法,用于向 textView 添加描边。

    @Override
    protected void onDraw(Canvas canvas) {
        if(_strokeWidth > 0) {
            //set paint to fill mode
            Paint p = getPaint();
            p.setStyle(Paint.Style.FILL);
            //draw the fill part of text
            super.onDraw(canvas);
            //save the text color
            int currentTextColor = getCurrentTextColor();
            //set paint to stroke mode and specify
            //stroke color and width
            p.setStyle(Paint.Style.STROKE);
            p.setStrokeWidth(_strokeWidth);
            setTextColor(_strokeColor);
            //draw text stroke
            super.onDraw(canvas);
            //revert the color back to the one
            //initially specified
            setTextColor(currentTextColor);
        } else {
            super.onDraw(canvas);
        }
    }

下面在 TextView 中绘制了字符的轮廓,但注意将字符本身剪掉,以免被覆盖。

OutlineTextView.java

public class OutlineTextView extends androidx.appcompat.widget.AppCompatTextView {
    private final Paint mOutlinePaint = new Paint();
    private final Path mOutlinePath = new Path();
    private float mStrokeWidth = 0f;

    public OutlineTextView(Context context) {
        super(context);
        init();
    }

    public OutlineTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public OutlineTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mOutlinePaint.setStrokeWidth(0f);
        mOutlinePaint.setStyle(Paint.Style.STROKE);
        mOutlinePaint.setColor(Color.RED);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        float xOffset = getLayout().getLineLeft(0) + getPaddingLeft();
        float baseline = getLayout().getLineBaseline(0) + getPaddingTop();
        getPaint().getTextPath(getText().toString(), 0, getText().length(), xOffset, baseline, mOutlinePath);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (mStrokeWidth > 0) {
            canvas.save();
            // The following insures that we don't draw inside the characters.
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
                canvas.clipPath(mOutlinePath, Region.Op.DIFFERENCE);
            } else {
                canvas.clipOutPath(mOutlinePath);
            }
            canvas.drawPath(mOutlinePath, mOutlinePaint);
            canvas.restore();
        }
    }

    public void setStrokeWidth(Float strokeWidth) {
        mStrokeWidth = strokeWidth;
        mOutlinePaint.setStrokeWidth(strokeWidth);
        invalidate();
    }
}