Fun Facts About OnMeasure() and OnLayout()

Help you understander better about measure and layout

Guowei Lv

2 minute read

Let’s understand more about Android view’s measure and layout process, and have some fun along the way.

Let’s say we have this:

<LinearLayout xmlns:android=""

        android:background="@color/design_default_color_primary" />

class StubbornView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

     * 1. Parent LinearLayout combines developer's requirements
     *    and the available space of itself into MeasureSpecs and
     *    pass them here.
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)

        val height = MeasureSpec.getSize(heightMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)

        Log.d("test", "Width: $width, mode: ${getMode(widthMode)}")
        Log.d("test", "Height: $height, mode: ${getMode(heightMode)}")

         * 2. StubbornView being naughty by ignoring parent's requirement and simply use 100px, 100px
        setMeasuredDimension(100, 100)

     * 3. Parent is not happy with the stubbornness of the child view, and choose to forcefully
     * carry out the match_parent rules.
    override fun layout(l: Int, t: Int, r: Int, b: Int) {
        Log.d("test", "layout(l: $left, t: $top, r: $right, b: $bottom)")

         * 4. Being really stubborn, we overwrite the parent's final decision again
         *    before the position data is saved!
        super.layout(l, t, l + 100, t + 100)

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

         * 5. Let's see what who wins. (StubbornView ofc)
        Log.d("test", "onLayout(l: $left, t: $top, r: $right, b: $bottom)")

    private fun getMode(mode: Int) = when (mode) {
        MeasureSpec.EXACTLY -> "EXACTLY"
        MeasureSpec.AT_MOST -> "AT_MOST"
        MeasureSpec.UNSPECIFIED -> "UNSPECIFIED"
        else -> ""

Here, the StubbornView really want to be 100px, 100px in size.

Try to change the parent to LinearLayout and see what is different?

comments powered by Disqus