Custom layouts let you arrange app elements exactly how you want. They help make your app look unique and fit your design needs.
Custom layouts in Android Kotlin
class MyCustomLayout(context: Context, attrs: AttributeSet?) : ViewGroup(context, attrs) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { // Measure children and set measured dimensions val widthSize = MeasureSpec.getSize(widthMeasureSpec) val heightSize = MeasureSpec.getSize(heightMeasureSpec) setMeasuredDimension(widthSize, heightSize) } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { // Position children inside this layout } }
You must override onMeasure to tell Android how big your layout and its children should be.
You must override onLayout to place each child view inside your layout.
class SimpleCustomLayout(context: Context) : ViewGroup(context) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val count = childCount var maxWidth = 0 var totalHeight = 0 for (i in 0 until count) { val child = getChildAt(i) measureChild(child, widthMeasureSpec, heightMeasureSpec) maxWidth = maxOf(maxWidth, child.measuredWidth) totalHeight += child.measuredHeight } val width = resolveSize(maxWidth, widthMeasureSpec) val height = resolveSize(totalHeight, heightMeasureSpec) setMeasuredDimension(width, height) } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { var currentTop = 0 for (i in 0 until childCount) { val child = getChildAt(i) child.layout(0, currentTop, child.measuredWidth, currentTop + child.measuredHeight) currentTop += child.measuredHeight } } }
class CenterCustomLayout(context: Context) : ViewGroup(context) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val child = getChildAt(0) measureChild(child, widthMeasureSpec, heightMeasureSpec) setMeasuredDimension( MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec) ) } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { val child = getChildAt(0) val left = (width - child.measuredWidth) / 2 val top = (height - child.measuredHeight) / 2 child.layout(left, top, left + child.measuredWidth, top + child.measuredHeight) } }
This custom layout stacks buttons vertically. Each button appears below the previous one. It measures all children to find the widest width and total height, then arranges them top to bottom.
class VerticalStackLayout(context: Context) : ViewGroup(context) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { var maxWidth = 0 var totalHeight = 0 for (i in 0 until childCount) { val child = getChildAt(i) measureChild(child, widthMeasureSpec, heightMeasureSpec) maxWidth = maxOf(maxWidth, child.measuredWidth) totalHeight += child.measuredHeight } val width = resolveSize(maxWidth, widthMeasureSpec) val height = resolveSize(totalHeight, heightMeasureSpec) setMeasuredDimension(width, height) } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { var currentTop = 0 for (i in 0 until childCount) { val child = getChildAt(i) child.layout(0, currentTop, child.measuredWidth, currentTop + child.measuredHeight) currentTop += child.measuredHeight } } } // Usage in an Activity or Fragment: // val layout = VerticalStackLayout(context) // layout.addView(Button(context).apply { setText("Button 1") }) // layout.addView(Button(context).apply { setText("Button 2") }) // setContentView(layout)
Always call measureChild or measureChildWithMargins inside onMeasure to measure children properly.
Use setMeasuredDimension to tell Android your layout's size after measuring.
In onLayout, use child.layout(left, top, right, bottom) to position each child view.
Custom layouts let you control exactly how child views are measured and placed.
You must override onMeasure and onLayout methods.
Custom layouts help create unique and flexible UI designs beyond standard layouts.