Skip to content
Related Articles

Related Articles

How to Create Custom Loading Button By Extending ViewClass in Android?

View Discussion
Improve Article
Save Article
  • Last Updated : 11 Aug, 2021
View Discussion
Improve Article
Save Article

In this article, we are going to create a custom loading button by extending the View class and animate properties of the custom button once it’s clicked. We had come across many times while downloading any file and keeping our eyes on the downloading progress. Here we will only create that custom button with animation. A sample GIF is given below to get an idea about what we are going to do in this article. Note that we are going to implement this project using the Kotlin language. 

 Create Custom Loading button by Extending ViewClass Sample GIF

Step by Step Implementation

Step 1: Create a New Project

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.

Step 2: Create a Sealed class, ButtonState which describes the state (like clicked, loading & completed) of the custom button. Below is the code for the ButtonState.kt file. 


package com.gfg.article.customloadingbutton
// describes the state of the custom button
sealed class ButtonState() {
    object Clicked : ButtonState()   // when button is clicked for downloading
    object Loading : ButtonState()   // when downloading is in progress
    object Completed : ButtonState() // when downloading is finished

Step 3: Create another class, LoadingButton in which everything related to the button like color, text, animation, etc will be defined. Make a constructor by annotating it with JvmOverloads. Below is the code for the LoadingButton.kt file. 


import android.animation.AnimatorInflater
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
import com.gfg.article.customloadingbutton.ButtonState
class LoadingButton @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {
    private var bgColor: Int = Color.BLACK
    private var textColor: Int = Color.BLACK // default color
    // tells the compiler that the value of a variable 
    // must never be cached as its value may change outside
    private var progress: Double = 0.0
    private var valueAnimator: ValueAnimator
    // observes the state of button
    private var buttonState: ButtonState by Delegates.observable(ButtonState.Completed) { p, old, new ->
    private val updateListener = ValueAnimator.AnimatorUpdateListener {
        progress = (it.animatedValue as Float).toDouble()
        invalidate()    // redraw the screen
        requestLayout() // when rectangular progress dimension changes
    // call after downloading is completed
    fun hasCompletedDownload() {
        // cancel the animation when file is downloaded
        buttonState = ButtonState.Completed
    // initialize
    init {
        isClickable = true
        valueAnimator = AnimatorInflater.loadAnimator(
            // properties for downloading progress is defined
        ) as ValueAnimator
        // initialize custom attributes of the button
        val attr = context.theme.obtainStyledAttributes(
        try {
            // button back-ground color
            bgColor = attr.getColor(
                ContextCompat.getColor(context, R.color.purple_200)
            // button text color
            textColor = attr.getColor(
                ContextCompat.getColor(context, R.color.white)
        } finally {
            // clearing all the data associated with attribute
    // set attributes of paint
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.FILL
        textAlign = Paint.Align.CENTER // button text alignment
        textSize = 55.0f //button text size
        typeface = Typeface.create("", Typeface.BOLD) // button text's font style
    override fun performClick(): Boolean {
        if (buttonState == ButtonState.Completed) buttonState = ButtonState.Loading
        return true
    // start the animation when button is clicked
    private fun animation() {
    override fun onDraw(canvas: Canvas) {
        paint.strokeWidth = 0f
        paint.color = bgColor
        // draw custom button
        canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
        // to show rectangular progress on custom button while file is downloading
        if (buttonState == ButtonState.Loading) {
            paint.color = Color.parseColor("#004349")
                0f, 0f,
                (width * (progress / 100)).toFloat(), height.toFloat(), paint
        // check the button state
        val buttonText = if (buttonState == ButtonState.Loading)
            resources.getString(R.string.loading)  // We are loading as button text
        else resources.getString( download as button text
        // write the text on custom button
        paint.color = textColor
        canvas.drawText(buttonText, (width / 2).toFloat(), ((height + 30) / 2).toFloat(), paint)

Step 4: Working with the XML file

Navigate to the app > res > layout > activity_main.xml and add the below code to that file. Below is the code for the activity_main.xml file. 


<?xml version="1.0" encoding="utf-8"?>
    <!--Custom Button-->
        app:textColor="@color/white" />

attrs.xml (under res -> values )


<?xml version="1.0" encoding="utf-8"?>
    <declare-styleable name="LoadingButton">
        <!--create custom attributes for the view-->
        <attr name="bgColor" format="integer" />
        <attr name="textColor" format="integer" />

loading_animation.xml (under res -> animator, create animator directory under res)


<?xml version="1.0" encoding="utf-8"?>
    android:valueType="floatType" />

Step 5: Working with the MainActivity.kt file

Go to the MainActivity.kt file and refer to the following code. Below is the code for the MainActivity.kt file. Comments are added inside the code to understand the code in more detail.


import android.os.Bundle
import android.widget.Toast
class MainActivity : AppCompatActivity() {
    lateinit var loadingButton: LoadingButton
    private var complete = false
    override fun onCreate(savedInstanceState: Bundle?) {
        loadingButton = findViewById(
        loadingButton.setOnClickListener {
            Toast.makeText(this, "File is downloading", Toast.LENGTH_LONG).show()
            complete = true
        if (complete) {
            // call when download completed


Source Code: Link

My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!