To get rid of unnecessary recompositions, we need to just move our width calculations into stage of placement of these objects

@Preview @Composable fun DoubleButtonPreview() { DoubleButton( text1 = "Smart search", onClick1 = {}, text2 = "Character search", onClick2 = {}, chosenIndex = 0 ) } @Composable fun DoubleButton( text1: String, onClick1: () -> Unit, text2: String, onClick2: () -> Unit, chosenIndex: Int ) { require(chosenIndex in listOf(0, 1)) val strokeWidth = 1.5.dp val mainShape = RoundedCornerShape(4.dp) Layout( modifier = Modifier.border(strokeWidth, Color.Black, mainShape), content = { DoubleButtonContent(text1, onClick1, text2, onClick2, chosenIndex, strokeWidth, mainShape) }, measurePolicy = { measurables, constraints -> val (buttonWidth, buttonHeight) = calculateButtonsWidthAndHeight(measurables, constraints) val placeables = listOf( measurables[0].measure(Constraints.fixed(buttonWidth, buttonHeight)), measurables[1].measure(Constraints.fixedHeight(buttonHeight)), measurables[2].measure(Constraints.fixed(buttonWidth, buttonHeight)) ) layout( width = buttonWidth * 2 + strokeWidth.roundToPx(), height = buttonHeight, placementBlock = { placeButtonsAndSeparator(buttonWidth, placeables) } ) } ) } private fun Placeable.PlacementScope.placeButtonsAndSeparator( buttonWidth: Int, placeables: List<Placeable> ) { var start = 0 val firstSpacesWidth = (buttonWidth - placeables[0].width) / 2 val secondSpacesWidth = (buttonWidth - placeables[2].width) / 2 start += firstSpacesWidth placeables[0].place(start, 0) start += placeables[0].width + firstSpacesWidth placeables[1].place(start, 0) start += placeables[1].width start += secondSpacesWidth placeables[2].place(start, 0) } private fun calculateButtonsWidthAndHeight( measurables: List<Measurable>, constraints: Constraints ): Pair<Int, Int> { val subButtons = measurables.let { listOf(it[0], it[2]) } val subButtonsWidths = subButtons.map { it.maxIntrinsicWidth(constraints.maxHeight) } val maxSubButtonWidth = subButtonsWidths.maxOrNull()!! val buttonHeight = subButtons.first().minIntrinsicHeight(maxSubButtonWidth) return Pair(maxSubButtonWidth, buttonHeight) } @Composable private fun DoubleButtonContent( text1: String, onClick1: () -> Unit, text2: String, onClick2: () -> Unit, chosenIndex: Int, strokeWidth: Dp, mainShape: RoundedCornerShape ) { val verticalTextButtonPadding = 8.dp val horizontalTextButtonPadding = 6.dp Box( modifier = Modifier .background( color = if (chosenIndex == 0) MaterialTheme.colors.primary.copy(alpha = 0.15f) else MaterialTheme.colors.surface, shape = mainShape.copy(topEnd = CornerSize(0.dp), bottomEnd = CornerSize(0.dp)) ) ) { Text( text = text1, color = if (chosenIndex == 0) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface, modifier = Modifier .onClick(onClick = onClick1) .padding(horizontalTextButtonPadding, verticalTextButtonPadding) .align(Alignment.Center) ) } Box( modifier = Modifier .fillMaxHeight() .width(strokeWidth) .background(Color.Black) ) Box( modifier = Modifier .background( color = if (chosenIndex == 1) MaterialTheme.colors.primary.copy(alpha = 0.15f) else MaterialTheme.colors.surface, shape = mainShape.copy(topEnd = CornerSize(0.dp), bottomEnd = CornerSize(0.dp)) ) ) { Text( text = text2, color = if (chosenIndex == 1) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface, modifier = Modifier .onClick(onClick = onClick2) .padding(horizontalTextButtonPadding, verticalTextButtonPadding) .align(Alignment.Center) ) } }