Understanding The Lifecycle of Custom View In Android - Kotlin

Last updated Sep 18, 2020

In Android all the widgets are based on View. Some times we need to create our own custom views for our application requirement. To create a Custom View we need to extend it from View Class.

Let's dive into understanding the lifecycle of custom view in Android.

To start implementing our own custom view, we will need to create a subclass of View and override some lifecycle callbacks methods of view. So first we need to understand the view lifecycle first.

The lifecycle are as follows : 

1. Constructor : When creating custom view we have to first override the constructor which initializes the view. There are the constructor available :

 

constructor(context: Context) : this(context, null){ }
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {

}

2. OnAttachedToWindow() : The method is called when the view is attached to the window. It let us know that the view can be active and now has surface on which it can draw and now we can also allocate any resource or create listeners.

override fun onAttachedToWindow() {
    super.onAttachedToWindow()
}

 

3. onMeasure() : The method is called to determine the dimensions of view that should be drawn. But in case its a viewgroup, it will call measure on each of its child views and then result can help determine its own size.

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}


@param widthMeasureSpec Horizontal space requirements as imposed by the parent

@param heightMeasureSpec Vertical space requirements as imposed by the parent

 

 

4. onLayout() : This is called after the measuring is done and now to position views on the screen. In case of viewgroup its called on each of its children.

 

override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
    super.onLayout(changed, left, top, right, bottom)
}

 

5. onDraw() : So after the sizes and positions are calucated in previous methods, now the view can be drawn based on them. It has Canvas object generated, on which the background will be drawn.

 

override fun onDraw(canvas: Canvas?) {
    super.onDraw(canvas)
}

 

Note : Try not to create objects in this method as it gets called frequently.

 

6. invalidate() : The call to this method invalidate the whole view. If the view is visible the onDraw(Canvas) will be called at some point in future. This method should only be called from a UI thread. If calling from a non-UI thread the call postInvalidate().

 

override fun invalidate() {
    super.invalidate()
}

 

Note :  We don't call onDraw() directly, instead we call invalidate(). To better optimization try to call this method as less frequently as possible.

 

7. requestLayout() : Call to this method happens when something has changed and it has invalidated the layout of this view. The call to this method will schedule a layout phase (measure -> layout -> draw) of the view tree. In the simple terms call requestLayout() when there is some change in layout view bound.

 

override fun requestLayout() {
    super.requestLayout()
}

 

Note : We should always call this method from UI thread. If calling from non-UI thread use Handler.

These all the methods require to draw a custom view. Hope you have a better idea on custom views lifecycle.

 

Custom TextView Example

import android.content.Context
import android.graphics.Canvas
import android.graphics.Typeface
import android.util.AttributeSet
import android.widget.TextView
import java.util.jar.Attributes

class CustomTextView: android.support.v7.widget.AppCompatTextView {


    constructor(context: Context) : this(context, null){ }
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        this.typeface= Typeface.createFromAsset(context?.assets,"valentina.ttf")
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
    }

    override fun invalidate() {
        super.invalidate()
    }

    override fun requestLayout() {
        super.requestLayout()
    }
}

 

Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

1852 Views