Android Kotlin: How to create a bordered circular ImageView

This code demonstrates how to create a circular ImageView with a customizable border in an Android app written in Kotlin. It achieves this by defining a custom extension function for a Bitmap object.

Breakdown:

  1. MainActivity.kt:

    • This file defines the main activity of the app.
    • It retrieves a bitmap image from the assets folder using the assetsToBitmap extension function.
    • It displays the original bitmap on the first ImageView (imageView).
    • The circularWithBorder extension function is then used to create a circular version of the bitmap with a specified border width and color. This modified bitmap is then displayed on the second ImageView (imageView2).
  2. circularWithBorder extension function:

    • This function takes a Bitmap object, context, border width (optional), and border color (optional) as arguments.
    • It calculates the required diameter for the circular image based on the original bitmap dimensions and the desired border width.
    • A new bitmap with the calculated diameter is created.
    • The original bitmap is drawn onto the center of the new canvas.
    • A Paint object is configured to draw a circular border with the specified width and color.
    • Finally, the drawCircle method is used to draw the border onto the canvas.
    • The function returns a RoundedBitmapDrawable instance representing the circular image with a border.
  3. dpToPixels extension function:

    • This is a helper function that converts a value in density-independent pixels (dp) to its equivalent pixel size based on the device's display metrics.
  4. assetsToBitmap extension function:

    • This function attempts to retrieve a bitmap image from the app's assets folder given a filename.
  5. activity_main.xml:

    • This file defines the layout for the main activity.
    • It contains two ImageView elements (imageView & imageView2) where the original and circular images will be displayed respectively.

Summary:

This code provides a reusable way to create bordered circular images from existing bitmaps in your Android app. The use of extension functions keeps the code clean and organized.


MainActivity.kt

package com.example.jetpack

import android.content.Context
import android.graphics.*
import android.os.Bundle
import android.util.TypedValue
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.drawable.RoundedBitmapDrawable
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import kotlinx.android.synthetic.main.activity_main.*
import java.io.IOException
import kotlin.math.min


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

        // get bitmap from assets folder
        val bitmap: Bitmap? = assetsToBitmap("flower10.jpg")

        // show the bitmap on first image view
        bitmap?.apply { imageView.setImageBitmap(this) }

        // make the bitmap circular with specified border
        bitmap?.circularWithBorder(
            context = applicationContext,
            borderWidth = 7.dpToPixels(applicationContext),
            borderColor = Color.parseColor("#004225")
        )?.apply {
            imageView2.setImageDrawable(this)
        }
    }
}


// extension function to make a bitmap circular with border
fun Bitmap.circularWithBorder(
    context: Context,
    borderWidth: Float = 25F,
    borderColor: Int = Color.BLACK
): RoundedBitmapDrawable? {
    // calculate the bitmap diameter and radius
    val diameter = (min(width, height) + borderWidth * 2).toInt()
    val radius = diameter / 2F

    val bitmap = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    canvas.drawColor(Color.WHITE)

    // draw bitmap at canvas center
    canvas.drawBitmap(
        this, // bitmap
        (diameter - this.width)/2F, // left
        (diameter - this.height)/2F, // top
        null // paint
    )

    // pa to draw circular border
    Paint().apply {
        style = Paint.Style.STROKE
        // stroke is always centered so double it
        strokeWidth = borderWidth * 2F
        color = borderColor
        isAntiAlias = true

        // draw circular border on canvas
        canvas.drawCircle(canvas.width / 2F,canvas.width / 2F,radius,this)
    }

    // return circular bitmap drawable with border
    return RoundedBitmapDrawableFactory.create(context.resources, bitmap).apply {
        isCircular = true
        setAntiAlias(true)
    }
}


// extension function to convert dp to equivalent pixels
fun Int.dpToPixels(context: Context):Float = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics
)


// extension function to get bitmap from assets
fun Context.assetsToBitmap(fileName: String): Bitmap?{
    return try {
        with(assets.open(fileName)){
            BitmapFactory.decodeStream(this)
        }
    } catch (e: IOException) { null }
}
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#EDEAE0"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="280dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@tools:sample/avatars" />

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="0dp"
        android:layout_height="280dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        tools:srcCompat="@tools:sample/avatars" />

</androidx.constraintlayout.widget.ConstraintLayout>
More android kotlin tutorials