Muhammad Waqas
Muhammad Waqas

Reputation: 97

How to add stroke on outside of TextView

Any ideas, code snippets are welcome!

I have created a CustomTextView class that extends AppCompatTextView and I did this to add stroke support to boring TextView. The problem is, Paint.Style.STROKE adds stroke on the inside of TextView. There should be something which allows us to choose between outer-stroke and inner-stroke.

P.S: I can share the complete CustomTextView class if needed, not a big deal.

This is the onDraw method from our CustomTextView which is used to add stroke to 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);
        }
    }

Upvotes: 2

Views: 829

Answers (1)

Cheticamp
Cheticamp

Reputation: 62841

The following draws the outline of the characters in a TextView but takes care to clip out the characters themselves so they are not drawn over.

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();
    }
}

enter image description here

Upvotes: 1

Related Questions