View with round corners not smooth

Viewed 2964

Have a look at my code below.

ShapeDrawable shapeDrawable = new ShapeDrawable(new RectShape());
    shapeDrawable.getPaint().setColor(Color.parseColor("#5a2705"));
    shapeDrawable.getPaint().setStyle(Style.STROKE);
    shapeDrawable.getPaint().setAntiAlias(true);
    shapeDrawable.getPaint().setStrokeWidth(2);
    shapeDrawable.getPaint().setPathEffect(new CornerPathEffect(10));

I am applying this as background to my LinearLayout, but the edges are not smooth. How can I fix this?

Here is the screenshot of how it looks.

enter image description here

7 Answers

I've encountered this problem recently and came up with a different solution. IMHO the best solution is to create your own Shape implementation and use it to create a ShapeDrawable.

Below is a simple implementation of rounded rectangle, that will allow you to inset it's border.

class InsetRoundRectShape(
    private var radiusArray: FloatArray = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f),
    private var inset: RectF = RectF()
): RectShape() {

    private var innerRect: RectF = RectF()
    private var path: Path = Path()

    constructor(radius: Float, inset: RectF): this(floatArrayOf(radius, radius, radius, radius, radius, radius, radius, radius), inset)
    constructor(radius: Float, inset: Float): this(radius, RectF(inset, inset, inset, inset))

    init {
        if (radiusArray.size < 8) {
            throw ArrayIndexOutOfBoundsException("radius array must have >= 8 values")
        }
    }

    override fun draw(canvas: Canvas, paint: Paint) {
        canvas.drawPath(path, paint)
    }

    override fun getOutline(outline: Outline) {
        super.getOutline(outline)

        val radius = radiusArray[0]
        if(radiusArray.any { it != radius }) {
            outline.setConvexPath(path)
            return
        }

        val r = rect()
        outline.setRoundRect(ceil(r.left).toInt(), ceil(r.top).toInt(), floor(r.right).toInt(), floor(r.bottom).toInt(), radius)
    }

    override fun onResize(w: Float, h: Float) {
        super.onResize(w, h)
        val r = rect()
        path.reset()
        innerRect.set(r.left + inset.left, r.top + inset.top, r.right - inset.right, r.bottom - inset.bottom)
        if(innerRect.width() <= w && innerRect.height() <= h) {
            path.addRoundRect(innerRect, radiusArray, Path.Direction.CCW)
        }
    }

    override fun clone(): InsetRoundRectShape {
        val shape = super.clone() as InsetRoundRectShape
        shape.radiusArray = radiusArray.clone()
        shape.inset = RectF(inset)
        shape.path = Path(path)
        return shape
    }
}

Create ShapeDrawable like this

//Inset has to be half of strokeWidth
ShapeDrawable(InsetRoundRectShape(10f, 4f)).apply {
    this.paint.color = Color.BLUE
    this.paint.style = Paint.Style.STROKE
    this.paint.strokeWidth = 8.dp
    this.invalidateSelf()
}
Related