How To Create Rounded Corner Layout in Android

HOW-TO-CREATE-ROUNDED-CORNER-LAYOUT-IN-ANDROID.png

1st April, 2023

Howdy Android developer! In this tutorial we are going to create a view container (layout) with rounded corners. This is a subclass of the Android FrameLayout class. Let’s get started.

Step 1: Create New Project

Create a new project in Android Studio from File ⇒ New Project and select Empty Activity from the templates.

Step 2: Create custom View

Open the project tool window by clicking on the project option from the Tool window bar. After that select the Android option from the drop-down and open the app → java hierarchy.

Right click on the package name and select New → Kotlin or Java class. Modify the code as below.

KotlinJava
content_copy light_mode remove
package com.androidchunk.myapp

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.util.TypedValue
import android.widget.FrameLayout

class RoundCornerLayout : FrameLayout {
    private var CORNER_RADIUS = 50f
    private var mCornerRadius = 0f
    private var mPaint: Paint? = null
    private var mMaskPaint: Paint? = null
    private var mMetrics: DisplayMetrics? = null

    constructor(context: Context) : super(context) {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs, 0) {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context,attrs,defStyleAttr) {
        init(context)
    }

    private fun init(context: Context) {
        mMetrics = context.resources.displayMetrics
        mCornerRadius =
            TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, mMetrics)
        mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mMaskPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
        mMaskPaint!!.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
        setWillNotDraw(false)
    }

    override fun draw(canvas: Canvas) {
        if (isInEditMode) {
            /*
              If you don't use this if clause,
              Android Studio's layout preview window will not showing anything!!!
             */
            super.draw(canvas)
        }
        val offscreenBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val offscreenCanvas = Canvas(offscreenBitmap)
        super.draw(offscreenCanvas)
        val maskBitmap = createMask(width, height)
        offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, mMaskPaint)
        canvas.drawBitmap(offscreenBitmap, 0f, 0f, mPaint)
    }

    private fun createMask(width: Int, height: Int): Bitmap {
        val mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
        val tempCanvas = Canvas(mask)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.color = Color.WHITE
        tempCanvas.drawRect(0F, 0F, width.toFloat(), height.toFloat(), paint)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
        tempCanvas.drawRoundRect(
            RectF(0F, 0F, width.toFloat(), height.toFloat()),
            mCornerRadius,
            mCornerRadius,
            paint
        )
        return mask
    }

    fun setCornerRadius(myCornerRadius: Float) {
        CORNER_RADIUS = myCornerRadius
        mCornerRadius =
            TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, mMetrics)
        this.invalidate()
    }
}
package com.androidchunk.myapp;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class RoundCornerLayout extends FrameLayout {
    private float CORNER_RADIUS = 50.f;
    private float mCornerRadius;
    private Paint mPaint;
    private Paint mMaskPaint;
    private DisplayMetrics mMetrics;

    public RoundCornerLayout(@NonNull Context context)
    {
        super(context);
        init(context);
    }

    public RoundCornerLayout(@NonNull Context context, @Nullable AttributeSet attrs)
    {
        super(context, attrs, 0);
        init(context);
    }

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


    private void init(Context context)
    {
        mMetrics = context.getResources().getDisplayMetrics();

        mCornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, mMetrics);

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        mMaskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        mMaskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

        setWillNotDraw(false);
    }

    @Override
    public void draw(Canvas canvas)
    {
        if (isInEditMode())
        {
            /*
              If you don't use this if clause,
              Android Studio's layout preview window will not showing anything!!!
             */
            super.draw(canvas);
        }

        Bitmap offscreenBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);

        Canvas offscreenCanvas = new Canvas(offscreenBitmap);

        super.draw(offscreenCanvas);

        Bitmap maskBitmap = createMask(getWidth(), getHeight());
        offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, mMaskPaint);
        canvas.drawBitmap(offscreenBitmap, 0f, 0f, mPaint);
    }

    private Bitmap createMask(int width, int height)
    {
        Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
        Canvas tempCanvas = new Canvas(mask);

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.WHITE);

        tempCanvas.drawRect(0, 0, width, height, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        tempCanvas.drawRoundRect(new RectF(0, 0, width, height), mCornerRadius, mCornerRadius, paint);

        return mask;
    }

    public void setCornerRadius(float myCornerRadius)
    {
        CORNER_RADIUS = myCornerRadius;
        mCornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, mMetrics);
        this.invalidate();
    }
}

Step 3: Add View to Layout XML

Rebuild the project. Now open the activity’s xml layout file, you will see the custom layout on the palette. Add it to the activity’s XML layout.

Add-Rounded-Corner-Layout-to-XML-Layout-Android.gif
XML
content_copy light_mode remove
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp"
    tools:context=".MainActivity">

    <com.androidchunk.myapp.RoundCornerLayout
        android:id="@+id/myRoundCornerLayout"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerHorizontal="true"
        android:background="#F50057" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="10dp"
        android:layout_marginBottom="10dp"
        android:background="#6A7478"
        android:orientation="vertical"
        android:padding="20dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Corner"
            android:textColor="#FFFFFF" />

        <SeekBar
            android:id="@+id/seekBar1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="15dp"
            android:max="100"
            android:progress="20" />
    </LinearLayout>
</RelativeLayout>

Step 4: Modify Your Activity

Finally, You will have to add custom layout control code in the activity. Change your activity as follows and run your app.

KotlinJava
content_copy light_mode remove
package com.androidchunk.myapp

import android.os.Bundle
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var mRoundCornerLayout: RoundCornerLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mRoundCornerLayout = findViewById(R.id.myRoundCornerLayout)

        val seekBar = findViewById<SeekBar>(R.id.seekBar1)

        seekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                runOnUiThread { mRoundCornerLayout.setCornerRadius(progress.toFloat()) }
            }
            override fun onStartTrackingTouch(seekBar: SeekBar) {}
            override fun onStopTrackingTouch(seekBar: SeekBar) {}
        })
    }
}
package com.androidchunk.myapp;

import android.os.Bundle;
import android.widget.SeekBar;

import androidx.appcompat.app.AppCompatActivity;

class MainActivity extends AppCompatActivity {
    private RoundCornerLayout mRoundCornerLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRoundCornerLayout = findViewById(R.id.myRoundCornerLayout);

        SeekBar seekBar = findViewById(R.id.seekBar1);

        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
        {
            @Override
            public void onProgressChanged(SeekBar seekBar, final int progress, boolean fromUser)
            {
                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        mRoundCornerLayout.setCornerRadius(progress);
                    }
                });
            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar){}

            @Override
            public void onStopTrackingTouch(SeekBar seekBar){}
        });
    }
}

Happy coding!

Leave a Reply