0
0
Android Kotlinmobile~20 mins

Custom layouts in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: CustomLayoutScreen
This screen demonstrates a custom layout that arranges child views in a circle.
Target UI
CustomLayoutScreen

+-----------------------+
|           o           |
|       o       o       |
|   o               o   |
|                       |
|       Center View      |
+-----------------------+
Create a custom ViewGroup that arranges its children evenly spaced in a circle.
Add at least 5 child views (e.g., TextViews or Buttons) inside the custom layout.
Center a TextView in the middle of the circle.
Ensure the layout measures and positions children correctly.
Use Kotlin and Android View system.
Starter Code
Android Kotlin
package com.example.customlayout

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class CustomCircleLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : ViewGroup(context, attrs) {

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        // TODO: Measure children and set measured dimensions
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        // TODO: Position children in a circle
    }
}

class CustomLayoutScreen : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val customLayout = CustomCircleLayout(this)

        // TODO: Add 5 child views and a center TextView

        setContentView(customLayout)
    }
}
Task 1
Task 2
Task 3
Task 4
Solution
Android Kotlin
package com.example.customlayout

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.graphics.Color
import android.view.Gravity

class CustomCircleLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : ViewGroup(context, attrs) {

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        var maxChildWidth = 0
        var maxChildHeight = 0

        // Measure children
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            measureChild(child, widthMeasureSpec, heightMeasureSpec)
            if (child.measuredWidth > maxChildWidth) maxChildWidth = child.measuredWidth
            if (child.measuredHeight > maxChildHeight) maxChildHeight = child.measuredHeight
        }

        val desiredWidth = maxChildWidth * 4
        val desiredHeight = maxChildHeight * 4

        val width = resolveSize(desiredWidth, widthMeasureSpec)
        val height = resolveSize(desiredHeight, heightMeasureSpec)

        setMeasuredDimension(width, height)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        val centerX = (r - l) / 2
        val centerY = (b - t) / 2
        val radius = (Math.min(centerX, centerY) * 0.7).toInt()

        val childCount = childCount
        if (childCount == 0) return

        // Layout center child (assumed last child)
        val centerChild = getChildAt(childCount - 1)
        val centerLeft = centerX - centerChild.measuredWidth / 2
        val centerTop = centerY - centerChild.measuredHeight / 2
        centerChild.layout(
            centerLeft,
            centerTop,
            centerLeft + centerChild.measuredWidth,
            centerTop + centerChild.measuredHeight
        )

        // Layout other children in circle
        val angleStep = 2 * Math.PI / (childCount - 1)

        for (i in 0 until childCount - 1) {
            val child = getChildAt(i)
            val angle = i * angleStep - Math.PI / 2 // start at top
            val childCenterX = (centerX + radius * Math.cos(angle)).toInt()
            val childCenterY = (centerY + radius * Math.sin(angle)).toInt()

            val left = childCenterX - child.measuredWidth / 2
            val top = childCenterY - child.measuredHeight / 2

            child.layout(
                left,
                top,
                left + child.measuredWidth,
                top + child.measuredHeight
            )
        }
    }
}

class CustomLayoutScreen : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val customLayout = CustomCircleLayout(this)

        // Add 5 child TextViews arranged in a circle
        for (i in 1..5) {
            val tv = TextView(this).apply {
                text = "Item $i"
                setBackgroundColor(Color.parseColor("#FFBB86FC"))
                setTextColor(Color.WHITE)
                gravity = Gravity.CENTER
                setPadding(20, 20, 20, 20)
            }
            customLayout.addView(tv)
        }

        // Add center TextView
        val centerView = TextView(this).apply {
            text = "Center View"
            setBackgroundColor(Color.parseColor("#FF6200EE"))
            setTextColor(Color.WHITE)
            gravity = Gravity.CENTER
            setPadding(30, 30, 30, 30)
        }
        customLayout.addView(centerView)

        setContentView(customLayout)
    }
}

We created a custom ViewGroup named CustomCircleLayout that arranges its children in a circle.

In onMeasure, we measure all children and decide the size of the layout based on the largest child size multiplied to give enough space for the circle.

In onLayout, we calculate the center point and radius. We place the last child in the center, and the other children evenly spaced around the circle using simple trigonometry.

In the activity, we add 5 TextViews as circle items and one center TextView labeled "Center View". Each child has background color and padding for visibility.

This example shows how to create a custom layout by overriding measurement and layout behavior in Android Kotlin.

Final Result
Completed Screen
CustomLayoutScreen

+-----------------------+
|           Item 1      |
|       Item 5     Item 2|
|   Item 4     Center View  Item 3   |
|                       |
+-----------------------+
The user sees 5 items arranged evenly in a circle around a center label.
No interactive behavior is implemented; this is a static layout demonstration.
Stretch Goal
Add touch feedback to each circle item that changes its background color when tapped.
💡 Hint
Use setOnClickListener on each child view and change background color inside the listener.