Use clipping to round corners of ViewGroup

Having defined this layout:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorAccent">

    <com.playground.RoundedRelativeLayout
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center"
        android:background="@color/colorPrimary" />

</FrameLayout>

Where RoundedRelativeLayout has following implementation:


    public class RoundedRelativeLayout extends RelativeLayout {

        private RectF rectF;
        private Path path = new Path();
        private float cornerRadius = 15;

        public RoundedRelativeLayout(Context context) {
            super(context);
        }

        public RoundedRelativeLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public RoundedRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            rectF = new RectF(0, 0, w, h);
            resetPath();
        }

        @Override
        public void draw(Canvas canvas) {
            int save = canvas.save();
            canvas.clipPath(path);
            super.draw(canvas);
            canvas.restoreToCount(save);
        }

        @Override
        protected void dispatchDraw(Canvas canvas) {
            int save = canvas.save();
            canvas.clipPath(path);
            super.dispatchDraw(canvas);
            canvas.restoreToCount(save);
        }

        private void resetPath() {
            path.reset();
            path.addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW);
            path.close();
        }
    }

You'll get following output:

The implementation is shamelessly stolen from RoundKornerLayouts project.


Here is a Kotlin version of azizbekian's answer:

class RoundedRelativeLayout(context: Context, attrs: AttributeSet) : RelativeLayout(context, attrs) {

    private lateinit var rectF: RectF
    private val path = Path()
    private var cornerRadius = 15f

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        rectF = RectF(0f, 0f, w.toFloat(), h.toFloat())
        resetPath()
    }

    override fun draw(canvas: Canvas) {
        val save = canvas.save()
        canvas.clipPath(path)
        super.draw(canvas)
        canvas.restoreToCount(save)
    }

    override fun dispatchDraw(canvas: Canvas) {
        val save = canvas.save()
        canvas.clipPath(path)
        super.dispatchDraw(canvas)
        canvas.restoreToCount(save)
    }

    private fun resetPath() {
        path.reset()
        path.addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW)
        path.close()
    }
}

Edit

As a bonus here's how to add the cornerRadius as an extra xml attribute you can set, just add this to res/values/styleable.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundedRelativeLayout">
        <attr name="cornerRadius" format="float"/>
    </declare-styleable>
</resources>

and then add this init method to the RoundedRelativeLayout class:

init {
    val ta = getContext().obtainStyledAttributes(attrs, R.styleable.RoundedRelativeLayout)
    cornerRadius = ta.getFloat(R.styleable.RoundedRelativeLayout_cornerRadius, 15f)
    ta.recycle()
}

And now when you use the layout you can set the cornerRadius in the xml like this:

<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto" <-- Make sure you include this line
        android:layout_width="80dp"
        android:layout_height="80dp">

    .
    .
    .

    <your.package.name.RoundedRelativeLayout
            android:id="@+id/roundedRect"
            app:cornerRadius="24"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    .
    .
    .